1 /*
2 * bmc_picmg.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
56 #include <OpenIPMI/ipmi_err.h>
57 #include <OpenIPMI/ipmi_msgbits.h>
58 #include <OpenIPMI/ipmi_picmg.h>
59
60 int
ipmi_mc_set_power(lmc_data_t * mc,unsigned char power,int gen_event)61 ipmi_mc_set_power(lmc_data_t *mc, unsigned char power, int gen_event)
62 {
63 lmc_data_t *dest_mc;
64 unsigned char data[13];
65 int rv;
66
67 if (mc->power_value == power)
68 return 0;
69
70 mc->power_value = power;
71
72 if ((mc->event_receiver == 0)
73 || (!gen_event))
74 return 0;
75
76 rv = ipmi_emu_get_mc_by_addr(mc->emu, mc->event_receiver, &dest_mc);
77 if (rv)
78 return 0;
79
80 /* Timestamp is ignored. */
81 data[0] = 0;
82 data[1] = 0;
83 data[2] = 0;
84 data[3] = 0;
85
86 data[4] = 0x20; /* These come from 0x20. */
87 data[5] = 0;
88 data[6] = 0x01; /* Version 1. */
89 data[7] = 0;
90 data[8] = 0x40; /* IPMB of the device being powered. */
91 data[9] = 0;
92 data[10] = power;
93 data[11] = 0;
94 data[12] = 0;
95
96 mc_new_event(dest_mc, 0xc0, data);
97
98 return 0;
99 }
100
101 static void
handle_set_power(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)102 handle_set_power(lmc_data_t *mc,
103 msg_t *msg,
104 unsigned char *rdata,
105 unsigned int *rdata_len,
106 void *cb_data)
107 {
108 if (check_msg_length(msg, 1, rdata, rdata_len))
109 return;
110
111 ipmi_mc_set_power(mc, msg->data[0], 1);
112
113 rdata[0] = 0;
114 *rdata_len = 1;
115 }
116
117 static void
handle_get_power(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)118 handle_get_power(lmc_data_t *mc,
119 msg_t *msg,
120 unsigned char *rdata,
121 unsigned int *rdata_len,
122 void *cb_data)
123 {
124 rdata[0] = 0;
125 rdata[1] = mc->power_value;
126 *rdata_len = 2;
127 }
128
129 static void
handle_set_hs_led(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)130 handle_set_hs_led(lmc_data_t *mc,
131 msg_t *msg,
132 unsigned char *rdata,
133 unsigned int *rdata_len,
134 void *cb_data)
135 {
136 if (check_msg_length(msg, 1, rdata, rdata_len))
137 return;
138
139 mc->leds[0].color = msg->data[0];
140
141 printf("Setting hotswap LED to %d\n", msg->data[0]);
142
143 rdata[0] = 0;
144 *rdata_len = 1;
145 }
146
147 static void
handle_get_hs_led(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)148 handle_get_hs_led(lmc_data_t *mc,
149 msg_t *msg,
150 unsigned char *rdata,
151 unsigned int *rdata_len,
152 void *cb_data)
153 {
154 rdata[0] = 0;
155 rdata[1] = mc->leds[0].color;
156 *rdata_len = 2;
157 }
158
159 cmd_handler_f oem0_netfn_handlers[256] = {
160 [0x01] = handle_set_power,
161 [0x02] = handle_get_power,
162 [0x03] = handle_set_hs_led,
163 [0x04] = handle_get_hs_led
164 };
165
166 static void
handle_picmg_get_properties(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)167 handle_picmg_get_properties(lmc_data_t *mc,
168 msg_t *msg,
169 unsigned char *rdata,
170 unsigned int *rdata_len,
171 void *cb_data)
172 {
173 rdata[0] = 0;
174 rdata[1] = IPMI_PICMG_GRP_EXT;
175 rdata[2] = 0x22; /* Version 2.2 */
176 rdata[3] = 0; /* Only have one FRU. */
177 rdata[4] = 0; /* As defined by spec. */
178 *rdata_len = 5;
179 }
180
181 static void
handle_picmg_get_address_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)182 handle_picmg_get_address_info(lmc_data_t *mc,
183 msg_t *msg,
184 unsigned char *rdata,
185 unsigned int *rdata_len,
186 void *cb_data)
187 {
188 atca_site_t *sites = mc->emu->atca_sites;
189 unsigned char hw_addr = mc->ipmb >> 1;
190 unsigned char devid = 0;
191 int i;
192
193 if (msg->len == 3) {
194 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
195 *rdata_len = 1;
196 return;
197 }
198
199 if (msg->len >= 2)
200 devid = msg->data[1];
201
202 if (msg->len >= 4) {
203 switch (msg->data[2]) {
204 case 0:
205 hw_addr = msg->data[3];
206 break;
207
208 case 1:
209 hw_addr = msg->data[3] >> 1;
210 break;
211
212 case 3:
213 if (msg->len < 5) {
214 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
215 *rdata_len = 1;
216 return;
217 }
218 for (i=0; i<128; i++) {
219 if (sites[i].valid
220 && (sites[i].site_type == msg->data[4])
221 && (sites[i].site_number == msg->data[3]))
222 {
223 break;
224 }
225 }
226 if (i == 128) {
227 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
228 *rdata_len = 1;
229 return;
230 }
231 hw_addr = i;
232 break;
233
234 default:
235 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
236 *rdata_len = 1;
237 return;
238 }
239 }
240
241 if ((hw_addr >= 128) || (!sites[hw_addr].valid) || (devid > 0)) {
242 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
243 *rdata_len = 1;
244 return;
245 }
246
247 rdata[0] = 0;
248 rdata[1] = IPMI_PICMG_GRP_EXT;
249 rdata[2] = hw_addr;
250 rdata[3] = hw_addr << 1;
251 rdata[4] = 0xff;
252 rdata[5] = devid;
253 rdata[6] = sites[hw_addr].site_number;
254 rdata[7] = sites[hw_addr].site_type;
255 *rdata_len = 8;
256 }
257
258 static void
handle_picmg_cmd_fru_control(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)259 handle_picmg_cmd_fru_control(lmc_data_t *mc,
260 msg_t *msg,
261 unsigned char *rdata,
262 unsigned int *rdata_len,
263 void *cb_data)
264 {
265 if (check_msg_length(msg, 3, rdata, rdata_len))
266 return;
267
268 if (msg->data[1] != 0) {
269 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
270 *rdata_len = 1;
271 return;
272 }
273
274 if (msg->data[2] >= 4) {
275 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
276 *rdata_len = 1;
277 return;
278 }
279
280 /* Nothing to reset. */
281 printf("Fru control set to %d\n", msg->data[2]);
282
283 rdata[0] = 0;
284 rdata[1] = IPMI_PICMG_GRP_EXT;
285 *rdata_len = 2;
286 }
287
288 static void
handle_picmg_cmd_get_fru_led_properties(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)289 handle_picmg_cmd_get_fru_led_properties(lmc_data_t *mc,
290 msg_t *msg,
291 unsigned char *rdata,
292 unsigned int *rdata_len,
293 void *cb_data)
294 {
295 if (check_msg_length(msg, 2, rdata, rdata_len))
296 return;
297
298 if (msg->data[1] != 0) {
299 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
300 *rdata_len = 1;
301 return;
302 }
303
304 rdata[0] = 0;
305 rdata[1] = IPMI_PICMG_GRP_EXT;
306 if (mc->num_leds <= 2) {
307 mc->num_leds = 2;
308 rdata[2] = 0x03; /* We support the first 2 LEDs. */
309 rdata[3] = 0x00;
310 } else if (mc->num_leds == 3) {
311 rdata[2] = 0x07; /* We support the first 3 LEDs. */
312 rdata[3] = 0x00;
313 } else {
314 rdata[2] = 0xf; /* We support the first 4 LEDs. */
315 rdata[3] = mc->num_leds = 4; /* How many more do we support? */
316 }
317 *rdata_len = 4;
318 }
319
320 static void
handle_picmg_cmd_get_led_color_capabilities(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)321 handle_picmg_cmd_get_led_color_capabilities(lmc_data_t *mc,
322 msg_t *msg,
323 unsigned char *rdata,
324 unsigned int *rdata_len,
325 void *cb_data)
326 {
327 unsigned int led;
328
329 if (check_msg_length(msg, 3, rdata, rdata_len))
330 return;
331
332 if (msg->data[1] != 0) {
333 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
334 *rdata_len = 1;
335 return;
336 }
337
338 led = msg->data[2];
339 if (led >= mc->num_leds) {
340 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
341 *rdata_len = 1;
342 return;
343 }
344
345 rdata[0] = 0;
346 rdata[1] = IPMI_PICMG_GRP_EXT;
347 rdata[2] = mc->leds[led].color_sup;
348 rdata[3] = mc->leds[led].def_loc_cnt_color;
349 rdata[4] = mc->leds[led].def_override_color;
350
351 *rdata_len = 5;
352 }
353
354 void
picmg_led_set(lmc_data_t * mc,sensor_t * sensor)355 picmg_led_set(lmc_data_t *mc, sensor_t *sensor)
356 {
357 printf("ATCA hot-swap state is %d\n", sensor->value);
358
359 switch (sensor->value) {
360 case 0:
361 case 3:
362 case 4:
363 /* off */
364 mc->leds[0].def_off_dur = 0;
365 mc->leds[0].def_on_dur = 0;
366 break;
367
368 case 1:
369 /* on */
370 mc->leds[0].def_off_dur = 0xff;
371 mc->leds[0].def_on_dur = 0;
372 break;
373
374 case 2:
375 /* long blink */
376 mc->leds[0].def_off_dur = 10;
377 mc->leds[0].def_on_dur = 90;
378 break;
379
380 case 5:
381 case 6:
382 /* short blink */
383 mc->leds[0].def_off_dur = 90;
384 mc->leds[0].def_on_dur = 10;
385 break;
386
387 case 7:
388 /* Nothing to do */
389 break;
390 }
391
392 if (mc->leds[0].loc_cnt) {
393 mc->leds[0].off_dur = mc->leds[0].def_off_dur;
394 mc->leds[0].on_dur = mc->leds[0].def_on_dur;
395 printf("Setting ATCA LED %d to %s %x %x %x\n",
396 0,
397 mc->leds[0].loc_cnt ? "local_control" : "override",
398 mc->leds[0].off_dur,
399 mc->leds[0].on_dur,
400 mc->leds[0].color);
401 }
402 }
403
404 static void
handle_picmg_cmd_set_fru_led_state(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)405 handle_picmg_cmd_set_fru_led_state(lmc_data_t *mc,
406 msg_t *msg,
407 unsigned char *rdata,
408 unsigned int *rdata_len,
409 void *cb_data)
410 {
411 unsigned int led;
412
413 if (check_msg_length(msg, 3, rdata, rdata_len))
414 return;
415
416 if (msg->data[1] != 0) {
417 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
418 *rdata_len = 1;
419 return;
420 }
421
422 led = msg->data[2];
423 if (led >= mc->num_leds) {
424 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
425 *rdata_len = 1;
426 return;
427 }
428
429 switch (msg->data[3]) {
430 case 0xfc: /* Local control */
431 if (!mc->leds[led].loc_cnt_sup) {
432 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
433 *rdata_len = 1;
434 return;
435 }
436
437 mc->leds[led].loc_cnt = 1;
438
439 mc->leds[led].off_dur = mc->leds[led].def_off_dur;
440 mc->leds[led].on_dur = mc->leds[led].def_on_dur;
441 mc->leds[led].color = mc->leds[led].def_loc_cnt_color;
442 break;
443
444 case 0xfb:
445 case 0xfd:
446 case 0xfe:
447 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
448 *rdata_len = 1;
449 return;
450
451 default: /* Override mode */
452 mc->leds[led].loc_cnt = 0;
453 mc->leds[led].off_dur = msg->data[3];
454 mc->leds[led].on_dur = msg->data[4];
455 if (msg->data[5] == 0xf)
456 mc->leds[led].color = mc->leds[led].def_override_color;
457 else if (msg->data[5] != 0xe) /* 0xe is don't change. */
458 mc->leds[led].color = msg->data[5];
459 }
460
461 printf("Setting ATCA LED %d to %s %x %x %x\n",
462 led,
463 mc->leds[led].loc_cnt ? "local_control" : "override",
464 mc->leds[led].off_dur,
465 mc->leds[led].on_dur,
466 mc->leds[led].color);
467
468 rdata[0] = 0;
469 rdata[1] = IPMI_PICMG_GRP_EXT;
470 *rdata_len = 2;
471 }
472
473 static void
handle_picmg_cmd_get_fru_led_state(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)474 handle_picmg_cmd_get_fru_led_state(lmc_data_t *mc,
475 msg_t *msg,
476 unsigned char *rdata,
477 unsigned int *rdata_len,
478 void *cb_data)
479 {
480 unsigned int led;
481
482 if (check_msg_length(msg, 3, rdata, rdata_len))
483 return;
484
485 if (msg->data[1] != 0) {
486 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
487 *rdata_len = 1;
488 return;
489 }
490
491 led = msg->data[2];
492 if (led >= mc->num_leds) {
493 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
494 *rdata_len = 1;
495 return;
496 }
497
498 rdata[0] = 0;
499 rdata[1] = IPMI_PICMG_GRP_EXT;
500 rdata[2] = 0x00;
501 if (mc->leds[led].loc_cnt_sup)
502 rdata[2] |= 0x01; /* Local control support */
503
504 if (mc->leds[led].loc_cnt) {
505 rdata[3] = mc->leds[led].off_dur;
506 rdata[4] = mc->leds[led].on_dur;
507 rdata[5] = mc->leds[led].color;
508 *rdata_len = 6;
509 } else {
510 rdata[2] |= 0x02; /* override state. */
511 rdata[3] = mc->leds[led].def_off_dur;
512 rdata[4] = mc->leds[led].def_on_dur;
513 rdata[5] = mc->leds[led].def_loc_cnt_color;
514 rdata[6] = mc->leds[led].off_dur;
515 rdata[7] = mc->leds[led].on_dur;
516 rdata[8] = mc->leds[led].color;
517 *rdata_len = 9;
518 }
519 }
520
521 static void
handle_picmg_cmd_get_shelf_address_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)522 handle_picmg_cmd_get_shelf_address_info(lmc_data_t *mc,
523 msg_t *msg,
524 unsigned char *rdata,
525 unsigned int *rdata_len,
526 void *cb_data)
527 {
528 handle_invalid_cmd(mc, rdata, rdata_len);
529 }
530
531 static void
handle_picmg_cmd_set_shelf_address_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)532 handle_picmg_cmd_set_shelf_address_info(lmc_data_t *mc,
533 msg_t *msg,
534 unsigned char *rdata,
535 unsigned int *rdata_len,
536 void *cb_data)
537 {
538 handle_invalid_cmd(mc, rdata, rdata_len);
539 }
540
541 static void
handle_picmg_cmd_set_ipmb_state(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)542 handle_picmg_cmd_set_ipmb_state(lmc_data_t *mc,
543 msg_t *msg,
544 unsigned char *rdata,
545 unsigned int *rdata_len,
546 void *cb_data)
547 {
548 handle_invalid_cmd(mc, rdata, rdata_len);
549 }
550
551 static void
handle_picmg_cmd_set_fru_activation_policy(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)552 handle_picmg_cmd_set_fru_activation_policy(lmc_data_t *mc,
553 msg_t *msg,
554 unsigned char *rdata,
555 unsigned int *rdata_len,
556 void *cb_data)
557 {
558 handle_invalid_cmd(mc, rdata, rdata_len);
559 }
560
561 static void
handle_picmg_cmd_get_fru_activation_policy(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)562 handle_picmg_cmd_get_fru_activation_policy(lmc_data_t *mc,
563 msg_t *msg,
564 unsigned char *rdata,
565 unsigned int *rdata_len,
566 void *cb_data)
567 {
568 handle_invalid_cmd(mc, rdata, rdata_len);
569 }
570
571 static void
handle_picmg_cmd_set_fru_activation(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)572 handle_picmg_cmd_set_fru_activation(lmc_data_t *mc,
573 msg_t *msg,
574 unsigned char *rdata,
575 unsigned int *rdata_len,
576 void *cb_data)
577 {
578 int op;
579 sensor_t *hssens;
580
581 if (check_msg_length(msg, 3, rdata, rdata_len))
582 return;
583
584 if (msg->data[1] != 0) {
585 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
586 *rdata_len = 1;
587 return;
588 }
589
590 if (! mc->hs_sensor) {
591 handle_invalid_cmd(mc, rdata, rdata_len);
592 return;
593 }
594
595 op = msg->data[2];
596 if (op >= 2) {
597 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
598 *rdata_len = 1;
599 return;
600 }
601
602 hssens = mc->hs_sensor;
603 switch (op) {
604 case 0:
605 if (bit_set(hssens->event_status, 3)
606 || bit_set(hssens->event_status, 4)
607 || bit_set(hssens->event_status, 5))
608 {
609 /* Transition to m6. */
610 ipmi_mc_sensor_set_bit_clr_rest(mc, hssens->lun, hssens->num,
611 6, 1);
612
613 /* Transition to m1. */
614 ipmi_mc_sensor_set_bit_clr_rest(mc, hssens->lun, hssens->num,
615 1, 1);
616 }
617 break;
618
619 case 1:
620 if (bit_set(hssens->event_status, 2)) {
621 /* Transition to m3. */
622 ipmi_mc_sensor_set_bit_clr_rest(mc, hssens->lun, hssens->num,
623 3, 1);
624
625 /* Transition to m4. */
626 ipmi_mc_sensor_set_bit_clr_rest(mc, hssens->lun, hssens->num,
627 4, 1);
628 }
629 }
630
631 rdata[0] = 0;
632 rdata[1] = IPMI_PICMG_GRP_EXT;
633 *rdata_len = 2;
634 }
635
636 static void
handle_picmg_cmd_get_device_locator_record(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)637 handle_picmg_cmd_get_device_locator_record(lmc_data_t *mc,
638 msg_t *msg,
639 unsigned char *rdata,
640 unsigned int *rdata_len,
641 void *cb_data)
642 {
643 handle_invalid_cmd(mc, rdata, rdata_len);
644 }
645
646 static void
handle_picmg_cmd_set_port_state(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)647 handle_picmg_cmd_set_port_state(lmc_data_t *mc,
648 msg_t *msg,
649 unsigned char *rdata,
650 unsigned int *rdata_len,
651 void *cb_data)
652 {
653 handle_invalid_cmd(mc, rdata, rdata_len);
654 }
655
656 static void
handle_picmg_cmd_get_port_state(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)657 handle_picmg_cmd_get_port_state(lmc_data_t *mc,
658 msg_t *msg,
659 unsigned char *rdata,
660 unsigned int *rdata_len,
661 void *cb_data)
662 {
663 handle_invalid_cmd(mc, rdata, rdata_len);
664 }
665
666 static void
handle_picmg_cmd_compute_power_properties(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)667 handle_picmg_cmd_compute_power_properties(lmc_data_t *mc,
668 msg_t *msg,
669 unsigned char *rdata,
670 unsigned int *rdata_len,
671 void *cb_data)
672 {
673 handle_invalid_cmd(mc, rdata, rdata_len);
674 }
675
676 static void
handle_picmg_cmd_set_power_level(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)677 handle_picmg_cmd_set_power_level(lmc_data_t *mc,
678 msg_t *msg,
679 unsigned char *rdata,
680 unsigned int *rdata_len,
681 void *cb_data)
682 {
683 handle_invalid_cmd(mc, rdata, rdata_len);
684 }
685
686 static void
handle_picmg_cmd_get_power_level(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)687 handle_picmg_cmd_get_power_level(lmc_data_t *mc,
688 msg_t *msg,
689 unsigned char *rdata,
690 unsigned int *rdata_len,
691 void *cb_data)
692 {
693 handle_invalid_cmd(mc, rdata, rdata_len);
694 }
695
696 static void
handle_picmg_cmd_renegotiate_power(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)697 handle_picmg_cmd_renegotiate_power(lmc_data_t *mc,
698 msg_t *msg,
699 unsigned char *rdata,
700 unsigned int *rdata_len,
701 void *cb_data)
702 {
703 handle_invalid_cmd(mc, rdata, rdata_len);
704 }
705
706 static void
handle_picmg_cmd_get_fan_speed_properties(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)707 handle_picmg_cmd_get_fan_speed_properties(lmc_data_t *mc,
708 msg_t *msg,
709 unsigned char *rdata,
710 unsigned int *rdata_len,
711 void *cb_data)
712 {
713 handle_invalid_cmd(mc, rdata, rdata_len);
714 }
715
716 static void
handle_picmg_cmd_set_fan_level(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)717 handle_picmg_cmd_set_fan_level(lmc_data_t *mc,
718 msg_t *msg,
719 unsigned char *rdata,
720 unsigned int *rdata_len,
721 void *cb_data)
722 {
723 handle_invalid_cmd(mc, rdata, rdata_len);
724 }
725
726 static void
handle_picmg_cmd_get_fan_level(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)727 handle_picmg_cmd_get_fan_level(lmc_data_t *mc,
728 msg_t *msg,
729 unsigned char *rdata,
730 unsigned int *rdata_len,
731 void *cb_data)
732 {
733 handle_invalid_cmd(mc, rdata, rdata_len);
734 }
735
736 static void
handle_picmg_cmd_bused_resource(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)737 handle_picmg_cmd_bused_resource(lmc_data_t *mc,
738 msg_t *msg,
739 unsigned char *rdata,
740 unsigned int *rdata_len,
741 void *cb_data)
742 {
743 handle_invalid_cmd(mc, rdata, rdata_len);
744 }
745
746 static void
handle_picmg_cmd_ipmb_link_info(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)747 handle_picmg_cmd_ipmb_link_info(lmc_data_t *mc,
748 msg_t *msg,
749 unsigned char *rdata,
750 unsigned int *rdata_len,
751 void *cb_data)
752 {
753 handle_invalid_cmd(mc, rdata, rdata_len);
754 }
755
756 static void
handle_picmg_cmd_shelf_power_allocation(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)757 handle_picmg_cmd_shelf_power_allocation(lmc_data_t *mc,
758 msg_t *msg,
759 unsigned char *rdata,
760 unsigned int *rdata_len,
761 void *cb_data)
762 {
763 if (check_msg_length(msg, 2, rdata, rdata_len))
764 return;
765
766 if (msg->data[1] > 1) {
767 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
768 *rdata_len = 1;
769 return;
770 }
771
772 rdata[0] = 0;
773 rdata[1] = IPMI_PICMG_GRP_EXT;
774 ipmi_set_uint16(rdata+2, 0);
775 if (msg->data[1] == 0) {
776 ipmi_set_uint16(rdata+4, 105);
777 ipmi_set_uint16(rdata+6, 227);
778 *rdata_len = 8;
779 } else {
780 ipmi_set_uint16(rdata+4, 227);
781 *rdata_len = 6;
782 }
783 }
784
785 static void
handle_picmg_cmd_shelf_manager_ipmb_address(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)786 handle_picmg_cmd_shelf_manager_ipmb_address(lmc_data_t *mc,
787 msg_t *msg,
788 unsigned char *rdata,
789 unsigned int *rdata_len,
790 void *cb_data)
791 {
792 handle_invalid_cmd(mc, rdata, rdata_len);
793 }
794
795 static void
handle_picmg_cmd_set_fan_policy(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)796 handle_picmg_cmd_set_fan_policy(lmc_data_t *mc,
797 msg_t *msg,
798 unsigned char *rdata,
799 unsigned int *rdata_len,
800 void *cb_data)
801 {
802 handle_invalid_cmd(mc, rdata, rdata_len);
803 }
804
805 static void
handle_picmg_cmd_get_fan_policy(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)806 handle_picmg_cmd_get_fan_policy(lmc_data_t *mc,
807 msg_t *msg,
808 unsigned char *rdata,
809 unsigned int *rdata_len,
810 void *cb_data)
811 {
812 handle_invalid_cmd(mc, rdata, rdata_len);
813 }
814
815
816 static void
handle_picmg_cmd_fru_control_capabilities(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)817 handle_picmg_cmd_fru_control_capabilities(lmc_data_t *mc,
818 msg_t *msg,
819 unsigned char *rdata,
820 unsigned int *rdata_len,
821 void *cb_data)
822 {
823 if (check_msg_length(msg, 2, rdata, rdata_len))
824 return;
825
826 if (msg->data[1] != 0) {
827 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
828 *rdata_len = 1;
829 return;
830 }
831
832 rdata[0] = 0;
833 rdata[1] = IPMI_PICMG_GRP_EXT;
834 rdata[2] = 0x0e;
835 *rdata_len = 3;
836 }
837
838 static void
handle_picmg_cmd_fru_inventory_device_lock_control(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)839 handle_picmg_cmd_fru_inventory_device_lock_control(lmc_data_t *mc,
840 msg_t *msg,
841 unsigned char *rdata,
842 unsigned int *rdata_len,
843 void *cb_data)
844 {
845 emu_data_t *emu = mc->emu;
846 uint16_t lock_id;
847 fru_data_t *fru;
848
849 if (mc->ipmb != 0x20) {
850 handle_invalid_cmd(mc, rdata, rdata_len);
851 return;
852 }
853
854 if (check_msg_length(msg, 5, rdata, rdata_len))
855 return;
856
857 if (msg->data[1] != 254) {
858 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
859 *rdata_len = 1;
860 return;
861 }
862
863 rdata[0] = 0;
864 rdata[1] = IPMI_PICMG_GRP_EXT;
865
866 switch (msg->data[2]) {
867 case 0:
868 rdata[2] = 0;
869 rdata[3] = 0;
870 ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp);
871 *rdata_len = 8;
872 break;
873
874 case 1:
875 if (emu->atca_fru_inv_locked) {
876 rdata[0] = 0x81;
877 *rdata_len = 1;
878 break;
879 }
880 fru = find_fru(mc, 254);
881 if (!fru || fru->length == 0) {
882 rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC;
883 *rdata_len = 1;
884 break;
885 }
886 emu->temp_fru_inv_data = malloc(fru->length);
887 if (!emu->temp_fru_inv_data) {
888 rdata[0] = IPMI_OUT_OF_SPACE_CC;
889 *rdata_len = 1;
890 break;
891 }
892 emu->temp_fru_inv_data_len = fru->length;
893 memcpy(emu->temp_fru_inv_data, fru->data,
894 emu->temp_fru_inv_data_len);
895
896 emu->atca_fru_inv_locked = 1;
897 emu->atca_fru_inv_curr_lock_id++;
898 ipmi_set_uint16(rdata+2, emu->atca_fru_inv_curr_lock_id);
899 ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp);
900 *rdata_len = 8;
901 emu->atca_fru_inv_lock_timeout = 20;
902 break;
903
904 case 2:
905 lock_id = ipmi_get_uint16(msg->data+3);
906 if (!emu->atca_fru_inv_locked
907 || (lock_id != emu->atca_fru_inv_curr_lock_id))
908 {
909 rdata[0] = 0x81;
910 *rdata_len = 1;
911 break;
912 }
913 emu->atca_fru_inv_locked = 0;
914 rdata[2] = 0;
915 rdata[3] = 0;
916 ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp);
917 *rdata_len = 8;
918 free(emu->temp_fru_inv_data);
919 emu->temp_fru_inv_data = NULL;
920 break;
921
922 case 3:
923 lock_id = ipmi_get_uint16(msg->data+3);
924 if (!emu->atca_fru_inv_locked
925 || (lock_id != emu->atca_fru_inv_curr_lock_id))
926 {
927 rdata[0] = 0x81;
928 *rdata_len = 1;
929 break;
930 }
931 emu->atca_fru_inv_locked = 0;
932 rdata[2] = 0;
933 rdata[3] = 0;
934 ipmi_set_uint32(rdata+4, emu->atca_fru_inv_curr_timestamp);
935 *rdata_len = 8;
936 emu->atca_fru_inv_curr_timestamp++;
937 /* FIXME - validate data. */
938 fru = find_fru(mc, 254);
939 if (!fru || fru->length == 0) {
940 rdata[0] = IPMI_NOT_SUPPORTED_IN_PRESENT_STATE_CC;
941 *rdata_len = 1;
942 break;
943 }
944 memcpy(fru->data, emu->temp_fru_inv_data,
945 emu->temp_fru_inv_data_len);
946 free(emu->temp_fru_inv_data);
947 emu->temp_fru_inv_data = NULL;
948 break;
949
950 default:
951 rdata[0] = IPMI_INVALID_DATA_FIELD_CC;
952 *rdata_len = 1;
953 break;
954 }
955 }
956
957 static void
handle_picmg_cmd_fru_inventory_device_write(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)958 handle_picmg_cmd_fru_inventory_device_write(lmc_data_t *mc,
959 msg_t *msg,
960 unsigned char *rdata,
961 unsigned int *rdata_len,
962 void *cb_data)
963 {
964 emu_data_t *emu = mc->emu;
965 uint16_t lock_id;
966 unsigned int offset;
967 unsigned int count;
968
969 if (mc->ipmb != 0x20) {
970 handle_invalid_cmd(mc, rdata, rdata_len);
971 return;
972 }
973
974 if (check_msg_length(msg, 6, rdata, rdata_len))
975 return;
976
977 if (msg->data[1] != 254) {
978 rdata[0] = IPMI_DESTINATION_UNAVAILABLE_CC;
979 *rdata_len = 1;
980 return;
981 }
982
983 lock_id = ipmi_get_uint16(msg->data+2);
984 if (!emu->atca_fru_inv_locked
985 || (lock_id != emu->atca_fru_inv_curr_lock_id))
986 {
987 rdata[0] = 0x80;
988 *rdata_len = 1;
989 return;
990 }
991
992 /* Reset the timer. */
993 emu->atca_fru_inv_lock_timeout = 20;
994
995 offset = ipmi_get_uint16(msg->data+4);
996 count = msg->len - 6;
997
998 if (offset >= emu->temp_fru_inv_data_len) {
999 rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1000 *rdata_len = 1;
1001 return;
1002 }
1003
1004 if ((offset+count) > emu->temp_fru_inv_data_len) {
1005 /* Too much data to put into FRU. */
1006 rdata[0] = IPMI_REQUESTED_DATA_LENGTH_EXCEEDED_CC;
1007 *rdata_len = 1;
1008 return;
1009 }
1010
1011 memcpy(emu->temp_fru_inv_data+offset, msg->data+6, count);
1012
1013 rdata[0] = 0;
1014 rdata[1] = IPMI_PICMG_GRP_EXT;
1015 rdata[2] = count;
1016 *rdata_len = 3;
1017 }
1018
1019 static void
handle_picmg_cmd_get_shelf_manager_ip_addresses(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1020 handle_picmg_cmd_get_shelf_manager_ip_addresses(lmc_data_t *mc,
1021 msg_t *msg,
1022 unsigned char *rdata,
1023 unsigned int *rdata_len,
1024 void *cb_data)
1025 {
1026 emu_data_t *emu = mc->emu;
1027 unsigned int addr;
1028 unsigned int count;
1029 emu_addr_t *ap = NULL;
1030 int i;
1031
1032 if (check_msg_length(msg, 2, rdata, rdata_len))
1033 return;
1034
1035 addr = msg->data[1];
1036
1037 for (count=0, i=0; i<MAX_EMU_ADDR; i++) {
1038 if (emu->addr[i].valid) {
1039 if (count == addr)
1040 ap = &(emu->addr[i]);
1041 count++;
1042 }
1043 }
1044
1045 if (addr >= count) {
1046 rdata[0] = IPMI_PARAMETER_OUT_OF_RANGE_CC;
1047 *rdata_len = 1;
1048 return;
1049 }
1050
1051 rdata[0] = 0;
1052 ipmi_set_uint32(rdata+1, emu->last_addr_change_time.tv_sec);
1053 rdata[5] = count;
1054 rdata[6] = 0x03;
1055 rdata[7] = addr - 1;
1056 rdata[8] = 20;
1057
1058 rdata[9] = ap->addr_type;
1059 if (addr == 0)
1060 rdata[9] |= 0x80;
1061 memcpy(rdata+10, ap->addr_data, ap->addr_len);
1062 *rdata_len = 10 + ap->addr_len;
1063 }
1064
1065 void handle_picmg_msg(lmc_data_t *mc,
1066 msg_t *msg,
1067 unsigned char *rdata,
1068 unsigned int *rdata_len,
1069 void *cb_data);
1070
1071 int
ipmi_emu_atca_enable(emu_data_t * emu)1072 ipmi_emu_atca_enable(emu_data_t *emu)
1073 {
1074 emu->atca_mode = 1;
1075 ipmi_emu_register_group_extension_handler(IPMI_PICMG_GRP_EXT,
1076 handle_picmg_msg, NULL);
1077 return 0;
1078 }
1079
1080 int
ipmi_emu_atca_set_site(emu_data_t * emu,unsigned char hw_address,unsigned char site_type,unsigned char site_number)1081 ipmi_emu_atca_set_site(emu_data_t *emu,
1082 unsigned char hw_address,
1083 unsigned char site_type,
1084 unsigned char site_number)
1085 {
1086 if (hw_address >= 128)
1087 return EINVAL;
1088
1089 emu->atca_sites[hw_address].valid = 1;
1090 emu->atca_sites[hw_address].hw_address = hw_address;
1091 emu->atca_sites[hw_address].site_type = site_type;
1092 emu->atca_sites[hw_address].site_number = site_number;
1093 return 0;
1094 }
1095
1096 void
handle_picmg_msg(lmc_data_t * mc,msg_t * msg,unsigned char * rdata,unsigned int * rdata_len,void * cb_data)1097 handle_picmg_msg(lmc_data_t *mc,
1098 msg_t *msg,
1099 unsigned char *rdata,
1100 unsigned int *rdata_len,
1101 void *cb_data)
1102 {
1103 switch(msg->cmd) {
1104 case IPMI_PICMG_CMD_GET_PROPERTIES:
1105 handle_picmg_get_properties(mc, msg, rdata, rdata_len, NULL);
1106 break;
1107
1108 case IPMI_PICMG_CMD_GET_ADDRESS_INFO:
1109 handle_picmg_get_address_info(mc, msg, rdata, rdata_len, NULL);
1110 break;
1111
1112 case IPMI_PICMG_CMD_FRU_CONTROL:
1113 handle_picmg_cmd_fru_control(mc, msg, rdata, rdata_len, NULL);
1114 break;
1115
1116 case IPMI_PICMG_CMD_GET_FRU_LED_PROPERTIES:
1117 handle_picmg_cmd_get_fru_led_properties(mc, msg, rdata, rdata_len,
1118 NULL);
1119 break;
1120
1121 case IPMI_PICMG_CMD_GET_LED_COLOR_CAPABILITIES:
1122 handle_picmg_cmd_get_led_color_capabilities(mc, msg, rdata, rdata_len,
1123 NULL);
1124 break;
1125
1126 case IPMI_PICMG_CMD_SET_FRU_LED_STATE:
1127 handle_picmg_cmd_set_fru_led_state(mc, msg, rdata, rdata_len, NULL);
1128 break;
1129
1130 case IPMI_PICMG_CMD_GET_FRU_LED_STATE:
1131 handle_picmg_cmd_get_fru_led_state(mc, msg, rdata, rdata_len, NULL);
1132 break;
1133
1134 case IPMI_PICMG_CMD_GET_SHELF_ADDRESS_INFO:
1135 handle_picmg_cmd_get_shelf_address_info(mc, msg, rdata, rdata_len,
1136 NULL);
1137 break;
1138
1139 case IPMI_PICMG_CMD_SET_SHELF_ADDRESS_INFO:
1140 handle_picmg_cmd_set_shelf_address_info(mc, msg, rdata, rdata_len,
1141 NULL);
1142 break;
1143
1144 case IPMI_PICMG_CMD_SET_IPMB_STATE:
1145 handle_picmg_cmd_set_ipmb_state(mc, msg, rdata, rdata_len, NULL);
1146 break;
1147
1148 case IPMI_PICMG_CMD_SET_FRU_ACTIVATION_POLICY:
1149 handle_picmg_cmd_set_fru_activation_policy(mc, msg, rdata, rdata_len,
1150 NULL);
1151 break;
1152
1153 case IPMI_PICMG_CMD_GET_FRU_ACTIVATION_POLICY:
1154 handle_picmg_cmd_get_fru_activation_policy(mc, msg, rdata, rdata_len,
1155 NULL);
1156 break;
1157
1158 case IPMI_PICMG_CMD_SET_FRU_ACTIVATION:
1159 handle_picmg_cmd_set_fru_activation(mc, msg, rdata, rdata_len, NULL);
1160 break;
1161
1162 case IPMI_PICMG_CMD_GET_DEVICE_LOCATOR_RECORD:
1163 handle_picmg_cmd_get_device_locator_record(mc, msg, rdata, rdata_len,
1164 NULL);
1165 break;
1166
1167 case IPMI_PICMG_CMD_SET_PORT_STATE:
1168 handle_picmg_cmd_set_port_state(mc, msg, rdata, rdata_len, NULL);
1169 break;
1170
1171 case IPMI_PICMG_CMD_GET_PORT_STATE:
1172 handle_picmg_cmd_get_port_state(mc, msg, rdata, rdata_len, NULL);
1173 break;
1174
1175 case IPMI_PICMG_CMD_COMPUTE_POWER_PROPERTIES:
1176 handle_picmg_cmd_compute_power_properties(mc, msg, rdata, rdata_len,
1177 NULL);
1178 break;
1179
1180 case IPMI_PICMG_CMD_SET_POWER_LEVEL:
1181 handle_picmg_cmd_set_power_level(mc, msg, rdata, rdata_len, NULL);
1182 break;
1183
1184 case IPMI_PICMG_CMD_GET_POWER_LEVEL:
1185 handle_picmg_cmd_get_power_level(mc, msg, rdata, rdata_len, NULL);
1186 break;
1187
1188 case IPMI_PICMG_CMD_RENEGOTIATE_POWER:
1189 handle_picmg_cmd_renegotiate_power(mc, msg, rdata, rdata_len, NULL);
1190 break;
1191
1192 case IPMI_PICMG_CMD_GET_FAN_SPEED_PROPERTIES:
1193 handle_picmg_cmd_get_fan_speed_properties(mc, msg, rdata, rdata_len,
1194 NULL);
1195 break;
1196
1197 case IPMI_PICMG_CMD_SET_FAN_LEVEL:
1198 handle_picmg_cmd_set_fan_level(mc, msg, rdata, rdata_len, NULL);
1199 break;
1200
1201 case IPMI_PICMG_CMD_GET_FAN_LEVEL:
1202 handle_picmg_cmd_get_fan_level(mc, msg, rdata, rdata_len, NULL);
1203 break;
1204
1205 case IPMI_PICMG_CMD_BUSED_RESOURCE:
1206 handle_picmg_cmd_bused_resource(mc, msg, rdata, rdata_len, NULL);
1207 break;
1208
1209 case IPMI_PICMG_CMD_IPMB_LINK_INFO:
1210 handle_picmg_cmd_ipmb_link_info(mc, msg, rdata, rdata_len, NULL);
1211 break;
1212
1213 case IPMI_PICMG_CMD_SHELF_POWER_ALLOCATION:
1214 handle_picmg_cmd_shelf_power_allocation(mc, msg, rdata, rdata_len,
1215 NULL);
1216 break;
1217
1218 case IPMI_PICMG_CMD_SHELF_MANAGER_IPMB_ADDRESS:
1219 handle_picmg_cmd_shelf_manager_ipmb_address(mc, msg, rdata, rdata_len,
1220 NULL);
1221 break;
1222
1223 case IPMI_PICMG_CMD_SET_FAN_POLICY:
1224 handle_picmg_cmd_set_fan_policy(mc, msg, rdata, rdata_len, NULL);
1225 break;
1226
1227 case IPMI_PICMG_CMD_GET_FAN_POLICY:
1228 handle_picmg_cmd_get_fan_policy(mc, msg, rdata, rdata_len, NULL);
1229 break;
1230
1231 case IPMI_PICMG_CMD_FRU_CONTROL_CAPABILITIES:
1232 handle_picmg_cmd_fru_control_capabilities(mc, msg, rdata, rdata_len,
1233 NULL);
1234 break;
1235
1236 case IPMI_PICMG_CMD_FRU_INVENTORY_DEVICE_LOCK_CONTROL:
1237 handle_picmg_cmd_fru_inventory_device_lock_control(mc, msg, rdata,
1238 rdata_len, NULL);
1239 break;
1240
1241 case IPMI_PICMG_CMD_FRU_INVENTORY_DEVICE_WRITE:
1242 handle_picmg_cmd_fru_inventory_device_write(mc, msg, rdata, rdata_len,
1243 NULL);
1244 break;
1245
1246 case IPMI_PICMG_CMD_GET_SHELF_MANAGER_IP_ADDRESSES:
1247 handle_picmg_cmd_get_shelf_manager_ip_addresses(mc, msg, rdata,
1248 rdata_len, NULL);
1249 break;
1250
1251 default:
1252 handle_invalid_cmd(mc, rdata, rdata_len);
1253 break;
1254 }
1255 }
1256