1 /*
2 * lanparm.c
3 *
4 * MontaVista IPMI code for configuring IPMI LAN connections
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2004 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
34 #include <string.h>
35 #include <math.h>
36 #include <stdio.h>
37
38 #include <OpenIPMI/ipmiif.h>
39 #include <OpenIPMI/ipmi_lanparm.h>
40 #include <OpenIPMI/ipmi_msgbits.h>
41 #include <OpenIPMI/ipmi_err.h>
42
43 #include <OpenIPMI/internal/opq.h>
44 #include <OpenIPMI/internal/locked_list.h>
45 #include <OpenIPMI/internal/ipmi_domain.h>
46 #include <OpenIPMI/internal/ipmi_mc.h>
47 #include <OpenIPMI/internal/ipmi_int.h>
48
49 #define IPMI_LANPARM_ATTR_NAME "ipmi_lanparm"
50
51 struct ipmi_lanparm_s
52 {
53 ipmi_mcid_t mc;
54 ipmi_domain_id_t domain;
55 unsigned char channel;
56
57 int refcount;
58
59 char name[IPMI_LANPARM_NAME_LEN];
60
61 unsigned int destroyed : 1;
62 unsigned int in_destroy : 1;
63 unsigned int locked : 1;
64 unsigned int in_list : 1;
65
66 /* Something to call when the destroy is complete. */
67 ipmi_lanparm_done_cb destroy_handler;
68 void *destroy_cb_data;
69
70 os_hnd_lock_t *lanparm_lock;
71
72 os_handler_t *os_hnd;
73
74 /* We serialize operations through here, since we are dealing with
75 a locked resource. */
76 opq_t *opq;
77 };
78
79 static int
lanparm_attr_init(ipmi_domain_t * domain,void * cb_data,void ** data)80 lanparm_attr_init(ipmi_domain_t *domain, void *cb_data, void **data)
81 {
82 locked_list_t *lanparml;
83
84 lanparml = locked_list_alloc(ipmi_domain_get_os_hnd(domain));
85 if (!lanparml)
86 return ENOMEM;
87
88 *data = lanparml;
89 return 0;
90 }
91
92 static void
lanparm_lock(ipmi_lanparm_t * lanparm)93 lanparm_lock(ipmi_lanparm_t *lanparm)
94 {
95 if (lanparm->os_hnd->lock)
96 lanparm->os_hnd->lock(lanparm->os_hnd, lanparm->lanparm_lock);
97 }
98
99 static void
lanparm_unlock(ipmi_lanparm_t * lanparm)100 lanparm_unlock(ipmi_lanparm_t *lanparm)
101 {
102 if (lanparm->os_hnd->lock)
103 lanparm->os_hnd->unlock(lanparm->os_hnd, lanparm->lanparm_lock);
104 }
105
106 static void
lanparm_get(ipmi_lanparm_t * lanparm)107 lanparm_get(ipmi_lanparm_t *lanparm)
108 {
109 lanparm_lock(lanparm);
110 lanparm->refcount++;
111 lanparm_unlock(lanparm);
112 }
113
114 static void internal_destroy_lanparm(ipmi_lanparm_t *lanparm);
115
116 static void
lanparm_put(ipmi_lanparm_t * lanparm)117 lanparm_put(ipmi_lanparm_t *lanparm)
118 {
119 lanparm_lock(lanparm);
120 lanparm->refcount--;
121 if (lanparm->refcount == 0) {
122 internal_destroy_lanparm(lanparm);
123 return;
124 }
125 lanparm_unlock(lanparm);
126 }
127
128 void
ipmi_lanparm_ref(ipmi_lanparm_t * lanparm)129 ipmi_lanparm_ref(ipmi_lanparm_t *lanparm)
130 {
131 lanparm_get(lanparm);
132 }
133
134 void
ipmi_lanparm_deref(ipmi_lanparm_t * lanparm)135 ipmi_lanparm_deref(ipmi_lanparm_t *lanparm)
136 {
137 lanparm_put(lanparm);
138 }
139
140 static int
destroy_lanparm(void * cb_data,void * item1,void * item2)141 destroy_lanparm(void *cb_data, void *item1, void *item2)
142 {
143 ipmi_lanparm_t *lanparm = item1;
144
145 lanparm_lock(lanparm);
146 lanparm->in_list = 1;
147 lanparm_unlock(lanparm);
148 return LOCKED_LIST_ITER_CONTINUE;
149 }
150
151 static void
lanparm_attr_destroy(void * cb_data,void * data)152 lanparm_attr_destroy(void *cb_data, void *data)
153 {
154 locked_list_t *lanparml = data;
155
156 locked_list_iterate(lanparml, destroy_lanparm, NULL);
157 locked_list_destroy(lanparml);
158 }
159
160 typedef struct iterate_lanparms_info_s
161 {
162 ipmi_lanparm_ptr_cb handler;
163 void *cb_data;
164 } iterate_lanparms_info_t;
165
166 static int
lanparms_handler(void * cb_data,void * item1,void * item2)167 lanparms_handler(void *cb_data, void *item1, void *item2)
168 {
169 iterate_lanparms_info_t *info = cb_data;
170 info->handler(item1, info->cb_data);
171 lanparm_put(item1);
172 return LOCKED_LIST_ITER_CONTINUE;
173 }
174
175 static int
lanparms_prefunc(void * cb_data,void * item1,void * item2)176 lanparms_prefunc(void *cb_data, void *item1, void *item2)
177 {
178 ipmi_lanparm_t *lanparm = item1;
179 lanparm_get(lanparm);
180 return LOCKED_LIST_ITER_CONTINUE;
181 }
182
183 void
ipmi_lanparm_iterate_lanparms(ipmi_domain_t * domain,ipmi_lanparm_ptr_cb handler,void * cb_data)184 ipmi_lanparm_iterate_lanparms(ipmi_domain_t *domain,
185 ipmi_lanparm_ptr_cb handler,
186 void *cb_data)
187 {
188 iterate_lanparms_info_t info;
189 ipmi_domain_attr_t *attr;
190 locked_list_t *lanparms;
191 int rv;
192
193 rv = ipmi_domain_find_attribute(domain, IPMI_LANPARM_ATTR_NAME,
194 &attr);
195 if (rv)
196 return;
197 lanparms = ipmi_domain_attr_get_data(attr);
198
199 info.handler = handler;
200 info.cb_data = cb_data;
201 locked_list_iterate_prefunc(lanparms, lanparms_prefunc,
202 lanparms_handler, &info);
203 ipmi_domain_attr_put(attr);
204 }
205
206 ipmi_mcid_t
ipmi_lanparm_get_mc_id(ipmi_lanparm_t * lanparm)207 ipmi_lanparm_get_mc_id(ipmi_lanparm_t *lanparm)
208 {
209 return lanparm->mc;
210 }
211
212 unsigned int
ipmi_lanparm_get_channel(ipmi_lanparm_t * lanparm)213 ipmi_lanparm_get_channel(ipmi_lanparm_t *lanparm)
214 {
215 return lanparm->channel;
216 }
217
218 int
ipmi_lanparm_get_name(ipmi_lanparm_t * lanparm,char * name,int length)219 ipmi_lanparm_get_name(ipmi_lanparm_t *lanparm, char *name, int length)
220 {
221 int slen;
222
223 if (length <= 0)
224 return 0;
225
226 /* Never changes, no lock needed. */
227 slen = strlen(lanparm->name);
228 if (slen == 0) {
229 if (name)
230 *name = '\0';
231 goto out;
232 }
233
234 if (name) {
235 memcpy(name, lanparm->name, slen);
236 name[slen] = '\0';
237 }
238 out:
239 return slen;
240 }
241
242 static int
check_lanparm_response_param(ipmi_lanparm_t * lanparm,ipmi_mc_t * mc,ipmi_msg_t * rsp,int len,char * func_name)243 check_lanparm_response_param(ipmi_lanparm_t *lanparm,
244 ipmi_mc_t *mc,
245 ipmi_msg_t *rsp,
246 int len,
247 char *func_name)
248 {
249 if (lanparm->destroyed) {
250 ipmi_log(IPMI_LOG_ERR_INFO,
251 "%slanparm.c(%s): "
252 "LANPARM was destroyed while an operation was in progress",
253 MC_NAME(mc), func_name);
254 return ECANCELED;
255 }
256
257 if (!mc) {
258 ipmi_log(IPMI_LOG_ERR_INFO,
259 "%slanparm.c(%s): "
260 "MC went away while LANPARM op was in progress",
261 MC_NAME(mc), func_name);
262 return ECANCELED;
263 }
264
265 if (rsp->data[0] != 0) {
266 #if 0
267 /* Sometimes this comes in and is valid (like when writing
268 parm 0 to value 2), just ignore it. */
269 /* We ignore 0x80, since that may be a valid error return for an
270 unsupported parameter. We also ignore 0x82, just to avoid
271 extraneous errors. */
272 if ((rsp->data[0] != 0x80) && (rsp->data[0] != 0x82))
273 ipmi_log(IPMI_LOG_ERR_INFO,
274 "%slanparm.c(%s): "
275 "IPMI error from LANPARM capabilities fetch: %x",
276 MC_NAME(mc), func_name, rsp->data[0]);
277 #endif
278 return IPMI_IPMI_ERR_VAL(rsp->data[0]);
279 }
280
281 if (rsp->data_len < len) {
282 ipmi_log(IPMI_LOG_ERR_INFO,
283 "%slanparm.c(%s): LANPARM capabilities too short",
284 MC_NAME(mc), func_name);
285 return EINVAL;
286 }
287 return 0;
288 }
289
290 int
ipmi_lanparm_alloc(ipmi_mc_t * mc,unsigned int channel,ipmi_lanparm_t ** new_lanparm)291 ipmi_lanparm_alloc(ipmi_mc_t *mc,
292 unsigned int channel,
293 ipmi_lanparm_t **new_lanparm)
294 {
295 ipmi_lanparm_t *lanparm = NULL;
296 int rv = 0;
297 ipmi_domain_t *domain = ipmi_mc_get_domain(mc);
298 int p, len;
299 locked_list_t *lanparml;
300 ipmi_domain_attr_t *attr;
301
302 CHECK_MC_LOCK(mc);
303
304 rv = ipmi_domain_register_attribute(domain, IPMI_LANPARM_ATTR_NAME,
305 lanparm_attr_init,
306 lanparm_attr_destroy,
307 NULL,
308 &attr);
309 if (rv)
310 return rv;
311 lanparml = ipmi_domain_attr_get_data(attr);
312
313 lanparm = ipmi_mem_alloc(sizeof(*lanparm));
314 if (!lanparm) {
315 rv = ENOMEM;
316 goto out;
317 }
318 memset(lanparm, 0, sizeof(*lanparm));
319
320 lanparm->refcount = 1;
321 lanparm->in_list = 1;
322 lanparm->mc = ipmi_mc_convert_to_id(mc);
323 lanparm->domain = ipmi_domain_convert_to_id(domain);
324 len = sizeof(lanparm->name);
325 p = ipmi_domain_get_name(domain, lanparm->name, len);
326 len -= p;
327 snprintf(lanparm->name+p, len, ".%d", ipmi_domain_get_unique_num(domain));
328 lanparm->os_hnd = ipmi_domain_get_os_hnd(domain);
329 lanparm->lanparm_lock = NULL;
330 lanparm->channel = channel & 0xf;
331
332 lanparm->opq = opq_alloc(lanparm->os_hnd);
333 if (!lanparm->opq) {
334 rv = ENOMEM;
335 goto out;
336 }
337
338 if (lanparm->os_hnd->create_lock) {
339 rv = lanparm->os_hnd->create_lock(lanparm->os_hnd,
340 &lanparm->lanparm_lock);
341 if (rv)
342 goto out;
343 }
344
345 if (! locked_list_add(lanparml, lanparm, NULL)) {
346 rv = ENOMEM;
347 goto out;
348 }
349
350 out:
351 if (rv) {
352 if (lanparm) {
353 if (lanparm->opq)
354 opq_destroy(lanparm->opq);
355 if (lanparm->lanparm_lock)
356 lanparm->os_hnd->destroy_lock(lanparm->os_hnd,
357 lanparm->lanparm_lock);
358 ipmi_mem_free(lanparm);
359 }
360 } else {
361 *new_lanparm = lanparm;
362 }
363 ipmi_domain_attr_put(attr);
364 return rv;
365 }
366
367 static void
internal_destroy_lanparm(ipmi_lanparm_t * lanparm)368 internal_destroy_lanparm(ipmi_lanparm_t *lanparm)
369 {
370 lanparm->in_destroy = 1;
371
372 /* We don't have to have a valid ipmi to destroy a lanparm, they
373 are designed to live after the ipmi has been destroyed. */
374
375 if (lanparm->in_list) {
376 int rv;
377 ipmi_domain_attr_t *attr;
378 locked_list_t *lanparml;
379
380 rv = ipmi_domain_id_find_attribute(lanparm->domain,
381 IPMI_LANPARM_ATTR_NAME,
382 &attr);
383 if (!rv) {
384 lanparm->refcount++;
385 lanparm->in_list = 0;
386 lanparm_unlock(lanparm);
387 lanparml = ipmi_domain_attr_get_data(attr);
388
389 locked_list_remove(lanparml, lanparm, NULL);
390 ipmi_domain_attr_put(attr);
391 lanparm_lock(lanparm);
392 /* While we were unlocked, someone may have come in and
393 grabbed the lanparm by iterating the list of lanparms.
394 That's ok, we just let them handle the destruction
395 since this code will not be entered again. */
396 if (lanparm->refcount != 1) {
397 lanparm->refcount--;
398 lanparm_unlock(lanparm);
399 return;
400 }
401 }
402 }
403 lanparm_unlock(lanparm);
404
405 if (lanparm->opq)
406 opq_destroy(lanparm->opq);
407
408 if (lanparm->lanparm_lock)
409 lanparm->os_hnd->destroy_lock(lanparm->os_hnd, lanparm->lanparm_lock);
410
411 /* Do this after we have gotten rid of all external dependencies,
412 but before it is free. */
413 if (lanparm->destroy_handler)
414 lanparm->destroy_handler(lanparm, 0, lanparm->destroy_cb_data);
415
416 ipmi_mem_free(lanparm);
417 }
418
419 int
ipmi_lanparm_destroy(ipmi_lanparm_t * lanparm,ipmi_lanparm_done_cb done,void * cb_data)420 ipmi_lanparm_destroy(ipmi_lanparm_t *lanparm,
421 ipmi_lanparm_done_cb done,
422 void *cb_data)
423
424 {
425 lanparm_lock(lanparm);
426 if (lanparm->in_list) {
427 int rv;
428 ipmi_domain_attr_t *attr;
429 locked_list_t *lanparml;
430
431 lanparm->in_list = 0;
432 rv = ipmi_domain_id_find_attribute(lanparm->domain,
433 IPMI_LANPARM_ATTR_NAME,
434 &attr);
435 if (!rv) {
436 lanparm_unlock(lanparm);
437 lanparml = ipmi_domain_attr_get_data(attr);
438
439 locked_list_remove(lanparml, lanparm, NULL);
440 ipmi_domain_attr_put(attr);
441 lanparm_lock(lanparm);
442 }
443 }
444
445 if (lanparm->destroyed) {
446 lanparm_unlock(lanparm);
447 return EINVAL;
448 }
449 lanparm->destroyed = 1;
450 lanparm_unlock(lanparm);
451 lanparm->destroy_handler = done;
452 lanparm->destroy_cb_data = cb_data;
453
454 lanparm_put(lanparm);
455 return 0;
456 }
457
458 typedef struct lanparm_fetch_handler_s
459 {
460 ipmi_lanparm_t *lanparm;
461 unsigned char parm;
462 unsigned char set;
463 unsigned char block;
464 ipmi_lanparm_get_cb handler;
465 void *cb_data;
466 unsigned char *data;
467 unsigned int data_len;
468 int rv;
469 } lanparm_fetch_handler_t;
470
471 /* This should be called with the lanparm locked. It will unlock the lanparm
472 before returning. */
473 static void
fetch_complete(ipmi_lanparm_t * lanparm,int err,lanparm_fetch_handler_t * elem)474 fetch_complete(ipmi_lanparm_t *lanparm, int err, lanparm_fetch_handler_t *elem)
475 {
476 if (lanparm->in_destroy)
477 goto out;
478
479 lanparm_unlock(lanparm);
480
481 if (elem->handler)
482 elem->handler(lanparm, err, elem->data, elem->data_len, elem->cb_data);
483
484 ipmi_mem_free(elem);
485
486 if (!lanparm->destroyed)
487 opq_op_done(lanparm->opq);
488
489 lanparm_put(lanparm);
490 return;
491
492 out:
493 lanparm_unlock(lanparm);
494 lanparm_put(lanparm);
495 }
496
497
498 static void
lanparm_config_fetched(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)499 lanparm_config_fetched(ipmi_mc_t *mc,
500 ipmi_msg_t *rsp,
501 void *rsp_data)
502 {
503 lanparm_fetch_handler_t *elem = rsp_data;
504 ipmi_lanparm_t *lanparm = elem->lanparm;
505 int rv;
506
507 rv = check_lanparm_response_param(lanparm, mc, rsp, 2,
508 "lanparm_config_fetched");
509
510 /* Skip over the completion code. */
511 elem->data = rsp->data + 1;
512 elem->data_len = rsp->data_len - 1;
513
514 lanparm_lock(lanparm);
515 fetch_complete(lanparm, rv, elem);
516 }
517
518 static void
start_config_fetch_cb(ipmi_mc_t * mc,void * cb_data)519 start_config_fetch_cb(ipmi_mc_t *mc, void *cb_data)
520 {
521 lanparm_fetch_handler_t *elem = cb_data;
522 ipmi_lanparm_t *lanparm = elem->lanparm;
523 unsigned char data[4];
524 ipmi_msg_t msg;
525 int rv;
526
527 lanparm_lock(lanparm);
528 if (lanparm->destroyed) {
529 ipmi_log(IPMI_LOG_ERR_INFO,
530 "%slanparm.c(start_config_fetch_cb): "
531 "LANPARM was destroyed while an operation was in progress",
532 MC_NAME(mc));
533 fetch_complete(lanparm, ECANCELED, elem);
534 goto out;
535 }
536
537 msg.data = data;
538 msg.netfn = IPMI_TRANSPORT_NETFN;
539 msg.cmd = IPMI_GET_LAN_CONFIG_PARMS_CMD;
540 data[0] = lanparm->channel;
541 data[1] = elem->parm;
542 data[2] = elem->set;
543 data[3] = elem->block;
544 msg.data_len = 4;
545 rv = ipmi_mc_send_command(mc, 0, &msg, lanparm_config_fetched, elem);
546
547 if (rv) {
548 ipmi_log(IPMI_LOG_ERR_INFO,
549 "%slanparm.c(start_config_fetch_cb): "
550 "LANPARM start_config_fetch: could not send cmd: %x",
551 MC_NAME(mc), rv);
552 fetch_complete(lanparm, ECANCELED, elem);
553 goto out;
554 }
555
556 lanparm_unlock(lanparm);
557 out:
558 return;
559 }
560
561 static int
start_config_fetch(void * cb_data,int shutdown)562 start_config_fetch(void *cb_data, int shutdown)
563 {
564 lanparm_fetch_handler_t *elem = cb_data;
565 int rv;
566
567 if (shutdown) {
568 ipmi_log(IPMI_LOG_ERR_INFO,
569 "lanparm.c(start_config_fetch): "
570 "LANPARM was destroyed while an operation was in progress");
571 lanparm_lock(elem->lanparm);
572 fetch_complete(elem->lanparm, ECANCELED, elem);
573 return OPQ_HANDLER_STARTED;
574 }
575
576 /* The read lock must be claimed before the lanparm lock to avoid
577 deadlock. */
578 rv = ipmi_mc_pointer_cb(elem->lanparm->mc, start_config_fetch_cb, elem);
579 if (rv) {
580 ipmi_log(IPMI_LOG_ERR_INFO,
581 "lanparm.c(start_config_fetch): "
582 "LANPARM's MC is not valid");
583 lanparm_lock(elem->lanparm);
584 fetch_complete(elem->lanparm, rv, elem);
585 }
586 return OPQ_HANDLER_STARTED;
587 }
588
589 int
ipmi_lanparm_get_parm(ipmi_lanparm_t * lanparm,unsigned int parm,unsigned int set,unsigned int block,ipmi_lanparm_get_cb done,void * cb_data)590 ipmi_lanparm_get_parm(ipmi_lanparm_t *lanparm,
591 unsigned int parm,
592 unsigned int set,
593 unsigned int block,
594 ipmi_lanparm_get_cb done,
595 void *cb_data)
596 {
597 lanparm_fetch_handler_t *elem;
598 int rv = 0;
599
600 if (lanparm->destroyed)
601 return EINVAL;
602
603 elem = ipmi_mem_alloc(sizeof(*elem));
604 if (!elem) {
605 ipmi_log(IPMI_LOG_ERR_INFO,
606 "lanparm.c(ipmi_lanparm_get_parm): "
607 "could not allocate the lanparm element");
608 return ENOMEM;
609 }
610
611 elem->handler = done;
612 elem->cb_data = cb_data;
613 elem->lanparm = lanparm;
614 elem->parm = parm;
615 elem->set = set;
616 elem->block = block;
617 elem->rv = 0;
618
619 if (!opq_new_op(lanparm->opq, start_config_fetch, elem, 0))
620 rv = ENOMEM;
621
622 if (rv)
623 ipmi_mem_free(elem);
624 else
625 lanparm_get(lanparm);
626
627 return rv;
628 }
629
630 typedef struct lanparm_set_handler_s
631 {
632 ipmi_lanparm_t *lanparm;
633 ipmi_lanparm_done_cb handler;
634 void *cb_data;
635 unsigned char data[MAX_IPMI_DATA_SIZE];
636 unsigned int data_len;
637 int rv;
638 } lanparm_set_handler_t;
639
640 /* This should be called with the lanparm locked. It will unlock the lanparm
641 before returning. */
642 static void
set_complete(ipmi_lanparm_t * lanparm,int err,lanparm_set_handler_t * elem)643 set_complete(ipmi_lanparm_t *lanparm, int err, lanparm_set_handler_t *elem)
644 {
645 if (lanparm->in_destroy)
646 goto out;
647
648 lanparm_unlock(lanparm);
649
650 if (elem->handler)
651 elem->handler(lanparm, err, elem->cb_data);
652
653 ipmi_mem_free(elem);
654
655 lanparm_lock(lanparm);
656 if (!lanparm->destroyed) {
657 lanparm_unlock(lanparm);
658 opq_op_done(lanparm->opq);
659 } else {
660 lanparm_unlock(lanparm);
661 }
662
663 lanparm_put(lanparm);
664 return;
665
666 out:
667 lanparm_unlock(lanparm);
668 lanparm_put(lanparm);
669 }
670
671 static void
lanparm_config_set(ipmi_mc_t * mc,ipmi_msg_t * rsp,void * rsp_data)672 lanparm_config_set(ipmi_mc_t *mc,
673 ipmi_msg_t *rsp,
674 void *rsp_data)
675 {
676 lanparm_set_handler_t *elem = rsp_data;
677 ipmi_lanparm_t *lanparm = elem->lanparm;
678 int rv;
679
680 rv = check_lanparm_response_param(lanparm, mc, rsp, 1,
681 "lanparm_config_set");
682
683 lanparm_lock(lanparm);
684 set_complete(lanparm, rv, elem);
685 }
686
687 static void
start_config_set_cb(ipmi_mc_t * mc,void * cb_data)688 start_config_set_cb(ipmi_mc_t *mc, void *cb_data)
689 {
690 lanparm_set_handler_t *elem = cb_data;
691 ipmi_lanparm_t *lanparm = elem->lanparm;
692 ipmi_msg_t msg;
693 int rv;
694
695 lanparm_lock(lanparm);
696 if (lanparm->destroyed) {
697 ipmi_log(IPMI_LOG_ERR_INFO,
698 "%slanparm.c(start_config_set_cb): "
699 "LANPARM was destroyed while an operation was in progress",
700 MC_NAME(mc));
701 set_complete(lanparm, ECANCELED, elem);
702 goto out;
703 }
704
705 msg.netfn = IPMI_TRANSPORT_NETFN;
706 msg.cmd = IPMI_SET_LAN_CONFIG_PARMS_CMD;
707 msg.data = elem->data;
708 msg.data_len = elem->data_len;
709 rv = ipmi_mc_send_command(mc, 0, &msg, lanparm_config_set, elem);
710
711 if (rv) {
712 ipmi_log(IPMI_LOG_ERR_INFO,
713 "%slanparm.c(start_config_set_cb): "
714 "LANPARM start_config_set: could not send cmd: %x",
715 MC_NAME(mc), rv);
716 set_complete(lanparm, ECANCELED, elem);
717 goto out;
718 }
719
720 lanparm_unlock(lanparm);
721 out:
722 return;
723 }
724
725 static int
start_config_set(void * cb_data,int shutdown)726 start_config_set(void *cb_data, int shutdown)
727 {
728 lanparm_set_handler_t *elem = cb_data;
729 int rv;
730
731 if (shutdown) {
732 ipmi_log(IPMI_LOG_ERR_INFO,
733 "lanparm.c(start_config_set): "
734 "LANPARM was destroyed while an operation was in progress");
735 lanparm_lock(elem->lanparm);
736 set_complete(elem->lanparm, ECANCELED, elem);
737 return OPQ_HANDLER_STARTED;
738 }
739
740 /* The read lock must be claimed before the lanparm lock to avoid
741 deadlock. */
742 rv = ipmi_mc_pointer_cb(elem->lanparm->mc, start_config_set_cb, elem);
743 if (rv) {
744 ipmi_log(IPMI_LOG_ERR_INFO,
745 "lanparm.c(start_config_set): "
746 "LANPARM's MC is not valid");
747 lanparm_lock(elem->lanparm);
748 set_complete(elem->lanparm, rv, elem);
749 }
750 return OPQ_HANDLER_STARTED;
751 }
752
753 int
ipmi_lanparm_set_parm(ipmi_lanparm_t * lanparm,unsigned int parm,unsigned char * data,unsigned int data_len,ipmi_lanparm_done_cb done,void * cb_data)754 ipmi_lanparm_set_parm(ipmi_lanparm_t *lanparm,
755 unsigned int parm,
756 unsigned char *data,
757 unsigned int data_len,
758 ipmi_lanparm_done_cb done,
759 void *cb_data)
760 {
761 lanparm_set_handler_t *elem;
762 int rv = 0;
763
764 if (lanparm->destroyed)
765 return EINVAL;
766
767 if (data_len > MAX_IPMI_DATA_SIZE-2)
768 return EINVAL;
769
770 elem = ipmi_mem_alloc(sizeof(*elem));
771 if (!elem) {
772 ipmi_log(IPMI_LOG_ERR_INFO,
773 "lanparm.c(ipmi_lanparm_set_parm): "
774 "could not allocate the lanparm element");
775 return ENOMEM;
776 }
777
778 elem->handler = done;
779 elem->cb_data = cb_data;
780 elem->lanparm = lanparm;
781 elem->data[0] = lanparm->channel;
782 elem->data[1] = parm;
783 memcpy(elem->data+2, data, data_len);
784 elem->data_len = data_len + 2;
785 elem->rv = 0;
786
787 if (!opq_new_op(lanparm->opq, start_config_set, elem, 0))
788 rv = ENOMEM;
789
790 if (rv)
791 ipmi_mem_free(elem);
792 else
793 lanparm_get(lanparm);
794
795 return rv;
796 }
797
798 typedef struct authtypes_s
799 {
800 unsigned int oem : 1;
801 unsigned int straight : 1;
802 unsigned int md5 : 1;
803 unsigned int md2 : 1;
804 unsigned int none : 1;
805 } authtypes_t;
806
807 typedef struct alert_dest_type_s
808 {
809 unsigned int alert_ack : 1;
810 unsigned int dest_type : 3;
811 unsigned int alert_retry_interval : 8;
812 unsigned int max_alert_retries : 3;
813 } alert_dest_type_t;
814
815 typedef struct alert_dest_addr_s
816 {
817 unsigned char dest_format;
818 unsigned char gw_to_use;
819 unsigned char dest_ip_addr[4];
820 unsigned char dest_mac_addr[6];
821
822 unsigned char dest_vlan_tag_type;
823 unsigned short dest_vlan_tag;
824 } alert_dest_addr_t;
825
826 struct ipmi_lan_config_s
827 {
828 /* Stuff for getting/setting the values. */
829 int curr_parm;
830 int curr_sel;
831
832 /* Not used for access, just for checking validity. */
833 ipmi_lanparm_t *my_lan;
834
835 /* Does this config hold the external LAN "set in progress" lock? */
836 int lan_locked;
837
838 /* Does the LAN config support locking? */
839 int lock_supported;
840
841 /* Used for deferred errors. */
842 int err;
843
844 ipmi_lanparm_done_cb set_done;
845 ipmi_lan_get_config_cb done;
846 void *cb_data;
847
848 authtypes_t auth_support;
849 authtypes_t auth_enable[5];
850 unsigned char ip_addr[4];
851 unsigned char ip_addr_source;
852 unsigned char mac_addr[6];
853 unsigned char subnet_mask[4];
854 unsigned char ipv4_ttl;
855 unsigned char ipv4_flags;
856 unsigned char ipv4_precedence;
857 unsigned char ipv4_tos;
858 unsigned char ipv4_header_parms_supported;
859 unsigned char primary_rmcp_port[2];
860 unsigned char primary_rmcp_port_supported;
861 unsigned char secondary_rmcp_port[2];
862 unsigned char secondary_rmcp_port_supported;
863 unsigned char bmc_generated_arps;
864 unsigned char bmc_generated_garps;
865 unsigned char arp_control_supported;
866 unsigned char garp_interval;
867 unsigned char garp_interval_supported;
868 unsigned char default_gateway_ip_addr[4];
869 unsigned char default_gateway_mac_addr[6];
870 unsigned char default_gateway_mac_addr_supported;
871 unsigned char backup_gateway_ip_addr[4];
872 unsigned char backup_gateway_ip_addr_supported;
873 unsigned char backup_gateway_mac_addr[6];
874 unsigned char backup_gateway_mac_addr_supported;
875 unsigned char community_string[18];
876
877 unsigned char vlan_id_supported;
878 unsigned short vlan_id;
879 unsigned char vlan_id_enable;
880
881 unsigned char vlan_priority_supported;
882 unsigned char vlan_priority;
883
884 unsigned char num_cipher_suites;
885 unsigned char cipher_suite_entries[16];
886 unsigned char max_priv_for_cipher_suite_supported;
887 unsigned char max_priv_for_cipher_suite[16];
888
889 /* See the note in the gnd function foro weirdness about this field. */
890 unsigned char num_alert_destinations;
891 unsigned char vlan_tag_supported;
892 alert_dest_type_t *alert_dest_type;
893 alert_dest_addr_t *alert_dest_addr;
894 };
895
896 typedef struct lanparms_s lanparms_t;
897 struct lanparms_s
898 {
899 unsigned int valid : 1;
900 unsigned int optional_offset : 8;
901 unsigned int length : 8;
902 unsigned int offset : 8;
903 /* Returns err. */
904 int (*get_handler)(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
905 unsigned char *data);
906 /* NULL if parameter is read-only */
907 void (*set_handler)(ipmi_lan_config_t *lanc, lanparms_t *lp,
908 unsigned char *data);
909 };
910
911 /* Byte array */
gba(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)912 static int gba(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
913 unsigned char *data)
914 {
915 unsigned char *opt = NULL;
916
917 if (lp->optional_offset)
918 opt = ((unsigned char *) lanc) + lp->optional_offset;
919
920 if (err) {
921 if (opt
922 && ((err == IPMI_IPMI_ERR_VAL(0x80))
923 /* Some systems incorrectly return 0xcc. Sigh. */
924 || (err == IPMI_IPMI_ERR_VAL(0xcc))))
925 {
926 *opt = 0;
927 return 0;
928 }
929 return err;
930 }
931
932 data++; /* Skip over the revision byte. */
933
934 if (opt)
935 *opt = 1;
936
937 memcpy(((unsigned char *) lanc)+lp->offset, data, lp->length);
938 return 0;
939 }
940
sba(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)941 static void sba(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
942 {
943 memcpy(data, ((unsigned char *) lanc)+lp->offset, lp->length);
944 }
945
946 #define GETAUTH(d, v) \
947 do { \
948 (d)->oem = (((v) >> 5) & 1); \
949 (d)->straight = (((v) >> 4) & 1); \
950 (d)->md5 = (((v) >> 2) & 1); \
951 (d)->md2 = (((v) >> 1) & 1); \
952 (d)->none = (((v) >> 0) & 1); \
953 } while (0)
954
955 #define SETAUTH(d) \
956 (((d)->oem << 5) \
957 | ((d)->straight << 4) \
958 | ((d)->md5 << 2) \
959 | ((d)->md2 << 1) \
960 | (d)->none)
961
962 /* Authentication Support */
gas(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)963 static int gas(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
964 unsigned char *data)
965 {
966 if (err)
967 return err;
968
969 data++; /* Skip over the revision byte. */
970
971 GETAUTH(&lanc->auth_support, *data);
972 return 0;
973 }
974
975 /* Authentication Enables */
gae(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)976 static int gae(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
977 unsigned char *data)
978 {
979 int i;
980
981 if (err)
982 return err;
983
984 data++; /* Skip over the revision byte. */
985
986 for (i=0; i<5; i++)
987 GETAUTH(&(lanc->auth_enable[i]), data[i]);
988 return 0;
989 }
990
sae(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)991 static void sae(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
992 {
993 int i;
994
995 for (i=0; i<5; i++)
996 data[i] = SETAUTH(&(lanc->auth_enable[i]));
997 }
998
999 /* IPV4 Header Parms */
ghp(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1000 static int ghp(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1001 unsigned char *data)
1002 {
1003 unsigned char *opt = NULL;
1004
1005 if (lp->optional_offset)
1006 opt = ((unsigned char *) lanc) + lp->optional_offset;
1007
1008 if (err) {
1009 if (opt
1010 && ((err == IPMI_IPMI_ERR_VAL(0x80))
1011 /* Some systems incorrectly return 0xcc. Sigh. */
1012 || (err == IPMI_IPMI_ERR_VAL(0xcc))))
1013 {
1014 *opt = 0;
1015 return 0;
1016 }
1017 return err;
1018 }
1019
1020 data++; /* Skip over the revision byte. */
1021
1022 if (opt)
1023 *opt = 1;
1024
1025 lanc->ipv4_ttl = data[0];
1026 lanc->ipv4_flags = (data[1] >> 5) & 0x7;
1027 lanc->ipv4_precedence = (data[2] >> 5) & 0x7;
1028 lanc->ipv4_tos = (data[2] >> 1) & 0xf;
1029 return 0;
1030 }
1031
shp(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1032 static void shp(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1033 {
1034 data[0] = lanc->ipv4_ttl;
1035 data[1] = lanc->ipv4_flags << 5;
1036 data[2] = (lanc->ipv4_precedence << 5) | (lanc->ipv4_tos << 1);
1037 }
1038
1039 /* Generated ARP control */
gga(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1040 static int gga(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1041 unsigned char *data)
1042 {
1043 unsigned char *opt = NULL;
1044
1045 if (lp->optional_offset)
1046 opt = ((unsigned char *) lanc) + lp->optional_offset;
1047
1048 if (err) {
1049 if (opt
1050 && ((err == IPMI_IPMI_ERR_VAL(0x80))
1051 /* Some systems incorrectly return 0xcc. Sigh. */
1052 || (err == IPMI_IPMI_ERR_VAL(0xcc))))
1053
1054 {
1055 *opt = 0;
1056 return 0;
1057 }
1058 return err;
1059 }
1060
1061 data++; /* Skip over the revision byte. */
1062
1063 if (opt)
1064 *opt = 1;
1065
1066 lanc->bmc_generated_arps = (data[0] >> 1) & 1;
1067 lanc->bmc_generated_garps = (data[0] >> 0) & 1;
1068 return 0;
1069 }
1070
sga(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1071 static void sga(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1072 {
1073 data[0] = (lanc->bmc_generated_arps << 1) | lanc->bmc_generated_garps;
1074 }
1075
1076 /* Number of Destinations */
gnd(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1077 static int gnd(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1078 unsigned char *data)
1079 {
1080 unsigned int num;
1081
1082 if (err)
1083 return err;
1084
1085 data++; /* Skip over the revision byte. */
1086
1087 lanc->num_alert_destinations = 0;
1088 num = data[0] & 0xf;
1089 if (lanc->alert_dest_type != NULL)
1090 ipmi_mem_free(lanc->alert_dest_type);
1091 lanc->alert_dest_type = NULL;
1092 if (lanc->alert_dest_addr != NULL)
1093 ipmi_mem_free(lanc->alert_dest_addr);
1094 lanc->alert_dest_addr = NULL;
1095
1096 if (num == 0)
1097 return 0;
1098
1099 /*
1100 * This is important! The number in this field is the number of
1101 * non-volatile destinations. There is a volatile destination
1102 * at zero that is always present, and at least on non-volatile
1103 * field is required if this paramter is non-zero.
1104 */
1105 num++;
1106
1107 lanc->alert_dest_type = ipmi_mem_alloc(sizeof(alert_dest_type_t) * num);
1108 if (!lanc->alert_dest_type)
1109 return ENOMEM;
1110
1111 lanc->alert_dest_addr = ipmi_mem_alloc(sizeof(alert_dest_addr_t) * num);
1112 if (!lanc->alert_dest_addr)
1113 return ENOMEM;
1114
1115 lanc->num_alert_destinations = num;
1116
1117 return 0;
1118 }
1119
1120 /* LAN Destination Type */
gdt(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1121 static int gdt(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1122 unsigned char *data)
1123 {
1124 int sel;
1125 alert_dest_type_t *dt;
1126
1127 if (err)
1128 return err;
1129
1130 data++; /* Skip over the revision byte. */
1131
1132 if ((data[0] & 0xf) != lanc->curr_sel) {
1133 /* Yikes, wrong selector came back! */
1134 ipmi_log(IPMI_LOG_WARNING,
1135 "lanparm.c(got_parm): "
1136 "Error fetching dest type %d,"
1137 " wrong selector came back, expecting %d, was %d."
1138 " Assuming it is %d.",
1139 lanc->curr_parm, lanc->curr_sel, data[0] & 0xf,
1140 lanc->curr_sel);
1141 }
1142
1143 sel = lanc->curr_sel;
1144 if (sel > lanc->num_alert_destinations)
1145 return 0; /* Another error check will get this later. */
1146
1147 dt = lanc->alert_dest_type + sel;
1148 dt->alert_ack = (data[1] >> 7) & 0x1;
1149 dt->dest_type = data[1] & 0x7;
1150 dt->alert_retry_interval = data[2];
1151 dt->max_alert_retries = data[3] & 0x7;
1152
1153 return 0;
1154 }
1155
1156 /* This one is special, the sel is in data[0]. */
sdt(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1157 static void sdt(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1158 {
1159 int sel;
1160 alert_dest_type_t *dt;
1161
1162 sel = data[0] & 0xf;
1163 dt = lanc->alert_dest_type + sel;
1164
1165 data[1] = (dt->alert_ack << 7) | dt->dest_type;
1166 data[2] = dt->alert_retry_interval;
1167 data[3] = dt->max_alert_retries;
1168 }
1169
1170 /* LAN Destination Address */
gda(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1171 static int gda(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1172 unsigned char *data)
1173 {
1174 int sel;
1175 alert_dest_addr_t *da;
1176
1177 if (err)
1178 return err;
1179
1180 data++; /* Skip over the revision byte. */
1181
1182 if ((data[0] & 0xf) != lanc->curr_sel) {
1183 /* Yikes, wrong selector came back! */
1184 ipmi_log(IPMI_LOG_ERR_INFO,
1185 "lanparm.c(got_parm): "
1186 "Error fetching dest addr %d,"
1187 " wrong selector came back, expecting %d, was %d."
1188 " Assuming it is %d.",
1189 lanc->curr_parm, lanc->curr_sel, data[0] & 0xf,
1190 lanc->curr_sel);
1191 }
1192
1193 sel = lanc->curr_sel;
1194 if (sel > lanc->num_alert_destinations)
1195 return 0; /* Another error check will get this later. */
1196
1197 da = lanc->alert_dest_addr + sel;
1198 da->dest_format = (data[1] >> 4) & 0xf;
1199 da->gw_to_use = data[2] & 1;
1200 memcpy(da->dest_ip_addr, data+3, 4);
1201 memcpy(da->dest_mac_addr, data+7, 6);
1202
1203 return 0;
1204 }
1205
1206 /* This one is special, the sel is in data[0]. */
sda(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1207 static void sda(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1208 {
1209 int sel;
1210 alert_dest_addr_t *da;
1211
1212 sel = data[0] & 0xf;
1213 da = lanc->alert_dest_addr + sel;
1214
1215 data[1] = da->dest_format << 4;
1216 data[2] = da->gw_to_use;
1217 memcpy(data+3, da->dest_ip_addr, 4);
1218 memcpy(data+7, da->dest_mac_addr, 6);
1219 }
1220
1221 /* IPMI_LANPARM_VLAN_ID */
gvi(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1222 static int gvi(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1223 unsigned char *data)
1224 {
1225 unsigned char *opt;
1226
1227 opt = ((unsigned char *) lanc) + lp->optional_offset;
1228 if (err) {
1229 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1230 *opt = 0;
1231 return 0;
1232 }
1233 return err;
1234 }
1235
1236 if (opt)
1237 *opt = 1;
1238
1239 data++; /* Skip over the revision byte. */
1240
1241 lanc->vlan_id_enable = (data[1] >> 7) & 1;
1242 lanc->vlan_id = ((data[1] & 0xf) << 8) | data[0];
1243 return 0;
1244 }
1245
svi(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1246 static void svi(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1247 {
1248 data[0] = lanc->vlan_id & 0xff;
1249 data[1] = (lanc->vlan_id_enable << 7) | ((lanc->vlan_id >> 8) & 0xf);
1250 }
1251
1252 /* IPMI_LANPARM_VLAN_PRIORITY */
gvp(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1253 static int gvp(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1254 unsigned char *data)
1255 {
1256 unsigned char *opt;
1257
1258 opt = ((unsigned char *) lanc) + lp->optional_offset;
1259 if (err) {
1260 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1261 *opt = 0;
1262 return 0;
1263 }
1264 return err;
1265 }
1266
1267 if (opt)
1268 *opt = 1;
1269
1270 data++; /* Skip over the revision byte. */
1271
1272 lanc->vlan_priority = data[0] & 0x07;
1273 return 0;
1274 }
1275
svp(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1276 static void svp(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1277 {
1278 data[0] = lanc->vlan_priority & 0x7;
1279 }
1280
1281 /* IPMI_LANPARM_NUM_CIPHER_SUITE_ENTRIES */
gnc(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1282 static int gnc(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1283 unsigned char *data)
1284 {
1285 if (err) {
1286 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1287 lanc->num_cipher_suites = 0;
1288 return 0;
1289 }
1290 return err;
1291 }
1292
1293 data++; /* Skip over the revision byte. */
1294
1295 lanc->num_cipher_suites = (data[0] & 0xf) + 1;
1296 return 0;
1297 }
1298
1299 /* IPMI_LANPARM_CIPHER_SUITE_ENTRY_SUPPORT */
gcs(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1300 static int gcs(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1301 unsigned char *data)
1302 {
1303 if (err)
1304 return err;
1305
1306 data++; /* Skip over the revision byte. */
1307
1308 memcpy(lanc->cipher_suite_entries, data+1, 16);
1309 return 0;
1310 }
1311
1312 /* IPMI_LANPARM_CIPHER_SUITE_ENTRY_PRIV */
gcp(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1313 static int gcp(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1314 unsigned char *data)
1315 {
1316 unsigned char *opt;
1317 int i, j;
1318
1319 opt = ((unsigned char *) lanc) + lp->optional_offset;
1320 if (err) {
1321 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1322 *opt = 0;
1323 return 0;
1324 }
1325 return err;
1326 }
1327
1328 if (opt)
1329 *opt = 1;
1330
1331 data++; /* Skip over the revision byte. */
1332 data++; /* Skip over reserved byte */
1333
1334 for (i=0, j=0; i<16; i+=2, j++) {
1335 lanc->max_priv_for_cipher_suite[i] = data[j] & 0xf;
1336 lanc->max_priv_for_cipher_suite[i+1] = (data[j] >> 4) & 0xf;
1337 }
1338 return 0;
1339 }
1340
scp(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1341 static void scp(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1342 {
1343 int i, j;
1344
1345 data[0] = 0;
1346 for (i=0, j=1; i<16; i+=2, j++) {
1347 data[j] = ((lanc->max_priv_for_cipher_suite[i] & 0xf)
1348 | ((lanc->max_priv_for_cipher_suite[i+1] & 0xf) << 4));
1349 }
1350 }
1351
1352 /* IPMI_LANPARM_DEST_VLAN_TAG */
gvt(ipmi_lan_config_t * lanc,lanparms_t * lp,int err,unsigned char * data)1353 static int gvt(ipmi_lan_config_t *lanc, lanparms_t *lp, int err,
1354 unsigned char *data)
1355 {
1356 int sel;
1357 alert_dest_addr_t *da;
1358 unsigned char *opt;
1359
1360 opt = ((unsigned char *) lanc) + lp->optional_offset;
1361 if (err) {
1362 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1363 *opt = 0;
1364 return 0;
1365 }
1366 return err;
1367 }
1368
1369 if (opt)
1370 *opt = 1;
1371
1372 data++; /* Skip over the revision byte. */
1373
1374 sel = data[0] & 0xf;
1375 if (sel > lanc->num_alert_destinations)
1376 return 0; /* Another error check will get this later. */
1377
1378 da = lanc->alert_dest_addr + sel;
1379
1380 da->dest_vlan_tag_type = (data[1] >> 4) & 0x0f;
1381 da->dest_vlan_tag = (data[3] << 8) | data[2];
1382 return 0;
1383 }
1384
svt(ipmi_lan_config_t * lanc,lanparms_t * lp,unsigned char * data)1385 static void svt(ipmi_lan_config_t *lanc, lanparms_t *lp, unsigned char *data)
1386 {
1387 int sel;
1388 alert_dest_addr_t *da;
1389
1390 sel = data[0] & 0xf;
1391 da = lanc->alert_dest_addr + sel;
1392
1393 data[1] = da->dest_vlan_tag_type << 4;
1394 data[2] = da->dest_vlan_tag & 0xff;
1395 data[3] = (da->dest_vlan_tag >> 8) & 0xff;
1396 }
1397
1398
1399
1400 #define OFFSET_OF(x) (((unsigned char *) &(((ipmi_lan_config_t *) NULL)->x)) \
1401 - ((unsigned char *) NULL))
1402
1403 #define NUM_LANPARMS 26
1404 static lanparms_t lanparms[NUM_LANPARMS] =
1405 {
1406 { 0, 0, 0, 0, NULL, NULL }, /* IPMI_LANPARM_SET_IN_PROGRESS */
1407 { 1, 0, 1, 0, gas, NULL }, /* IPMI_LANPARM_AUTH_TYPE_SUPPORT */
1408 { 1, 0, 5, 0, gae, sae }, /* IPMI_LANPARM_AUTH_TYPE_ENABLES */
1409 #undef F
1410 #define F OFFSET_OF(ip_addr)
1411 { 1, 0, 4, F, gba, sba }, /* IPMI_LANPARM_IP_ADDRESS */
1412 #undef F
1413 #define F OFFSET_OF(ip_addr_source)
1414 { 1, 0, 1, F, gba, sba }, /* IPMI_LANPARM_IP_ADDRESS_SRC */
1415 #undef F
1416 #define F OFFSET_OF(mac_addr)
1417 { 1, 0, 6, F, gba, sba }, /* IPMI_LANPARM_MAC_ADDRESS */
1418 #undef F
1419 #define F OFFSET_OF(subnet_mask)
1420 { 1, 0, 4, F, gba, sba }, /* IPMI_LANPARM_SUBNET_MASK */
1421 #undef S
1422 #define S OFFSET_OF(ipv4_header_parms_supported)
1423 { 1, S, 3, 0, ghp, shp }, /* IPMI_LANPARM_IPV4_HDR_PARMS */
1424 #undef F
1425 #define F OFFSET_OF(primary_rmcp_port)
1426 #undef S
1427 #define S OFFSET_OF(primary_rmcp_port_supported)
1428 { 1, S, 2, F, gba, sba }, /* IPMI_LANPARM_PRIMARY_RMCP_PORT */
1429 #undef F
1430 #define F OFFSET_OF(secondary_rmcp_port)
1431 #undef S
1432 #define S OFFSET_OF(secondary_rmcp_port_supported)
1433 { 1, S, 2, F, gba, sba }, /* IPMI_LANPARM_SECONDARY_RMCP_PORT */
1434 #undef S
1435 #define S OFFSET_OF(arp_control_supported)
1436 { 1, S, 1, 0, gga, sga }, /* IPMI_LANPARM_BMC_GENERATED_ARP_CNTL */
1437 #undef F
1438 #define F OFFSET_OF(garp_interval)
1439 #undef S
1440 #define S OFFSET_OF(garp_interval_supported)
1441 { 1, S, 1, F, gba, sba }, /* IPMI_LANPARM_GRATUIDOUS_ARP_INTERVAL */
1442 #undef F
1443 #define F OFFSET_OF(default_gateway_ip_addr)
1444 { 1, 0, 4, F, gba, sba }, /* IPMI_LANPARM_DEFAULT_GATEWAY_ADDR */
1445 #undef F
1446 #define F OFFSET_OF(default_gateway_mac_addr)
1447 #undef S
1448 #define S OFFSET_OF(default_gateway_mac_addr_supported)
1449 { 1, S, 6, F, gba, sba }, /* IPMI_LANPARM_DEFAULT_GATEWAY_MAC_ADDR */
1450 #undef F
1451 #define F OFFSET_OF(backup_gateway_ip_addr)
1452 #undef S
1453 #define S OFFSET_OF(backup_gateway_ip_addr_supported)
1454 { 1, S, 4, F, gba, sba }, /* IPMI_LANPARM_BACKUP_GATEWAY_ADDR */
1455 #undef F
1456 #define F OFFSET_OF(backup_gateway_mac_addr)
1457 #undef S
1458 #define S OFFSET_OF(backup_gateway_mac_addr_supported)
1459 { 1, S, 6, F, gba, sba }, /* IPMI_LANPARM_BACKUP_GATEWAY_MAC_ADDR */
1460 #undef F
1461 #define F OFFSET_OF(community_string)
1462 { 1, 0, 18, F, gba, sba }, /* IPMI_LANPARM_COMMUNITY_STRING */
1463 { 1, 0, 1, 0, gnd, NULL }, /* IPMI_LANPARM_NUM_DESTINATIONS */
1464 { 1, 0, 4, 0, gdt, sdt }, /* IPMI_LANPARM_DEST_TYPE */
1465 { 1, 0, 13, 0, gda, sda }, /* IPMI_LANPARM_DEST_ADDR */
1466 #undef S
1467 #define S OFFSET_OF(vlan_id_supported)
1468 { 1, S, 2, 0, gvi, svi }, /* IPMI_LANPARM_VLAN_ID */
1469 #undef S
1470 #define S OFFSET_OF(vlan_priority_supported)
1471 { 1, S, 1, 0, gvp, svp }, /* IPMI_LANPARM_VLAN_PRIORITY */
1472 { 1, 0, 1, 0, gnc, NULL }, /* IPMI_LANPARM_NUM_CIPHER_SUITE_ENTRIES */
1473 { 1, 0, 17, 0, gcs, NULL }, /* IPMI_LANPARM_CIPHER_SUITE_ENTRY_SUPPORT */
1474 #undef S
1475 #define S OFFSET_OF(max_priv_for_cipher_suite_supported)
1476 { 1, S, 9, 0, gcp, scp }, /* IPMI_LANPARM_CIPHER_SUITE_ENTRY_PRIV */
1477 #undef S
1478 #define S OFFSET_OF(vlan_tag_supported)
1479 { 1, S, 4, 0, gvt, svt }, /* IPMI_LANPARM_DEST_VLAN_TAG */
1480 };
1481
1482 static void
err_lock_cleared(ipmi_lanparm_t * lanparm,int err,void * cb_data)1483 err_lock_cleared(ipmi_lanparm_t *lanparm,
1484 int err,
1485 void *cb_data)
1486 {
1487 ipmi_lan_config_t *lanc = cb_data;
1488
1489 if (lanc->done)
1490 lanc->done(lanparm, lanc->err, NULL, lanc->cb_data);
1491 ipmi_lan_free_config(lanc);
1492 lanparm->locked = 0;
1493 lanparm_put(lanparm);
1494 }
1495
1496 static void
got_parm(ipmi_lanparm_t * lanparm,int err,unsigned char * data,unsigned int data_len,void * cb_data)1497 got_parm(ipmi_lanparm_t *lanparm,
1498 int err,
1499 unsigned char *data,
1500 unsigned int data_len,
1501 void *cb_data)
1502 {
1503 ipmi_lan_config_t *lanc = cb_data;
1504 lanparms_t *lp = &(lanparms[lanc->curr_parm]);
1505
1506 /* Check the length, and don't forget the revision byte must be added. */
1507 if ((!err) && (data_len < (unsigned int) (lp->length+1))) {
1508 if ((data_len == 1) && (lp->optional_offset)) {
1509 /* Some systems return zero-length data for optional parms. */
1510 unsigned char *opt = ((unsigned char *)lanc) + lp->optional_offset;
1511 *opt = 0;
1512 goto next_parm;
1513 }
1514 ipmi_log(IPMI_LOG_ERR_INFO,
1515 "lanparm.c(got_parm): "
1516 " Invalid data length on parm %d was %d, should have been %d",
1517 lanc->curr_parm, data_len, lp->length+1);
1518 err = EINVAL;
1519 goto done;
1520 }
1521
1522 err = lp->get_handler(lanc, lp, err, data);
1523 if (err) {
1524 ipmi_log(IPMI_LOG_ERR_INFO,
1525 "lanparm.c(got_parm): "
1526 "Error fetching parm %d: %x",
1527 lanc->curr_parm, err);
1528 goto done;
1529 }
1530
1531 next_parm:
1532 switch (lanc->curr_parm) {
1533 case IPMI_LANPARM_NUM_DESTINATIONS:
1534 if (lanc->num_alert_destinations == 0)
1535 lanc->curr_parm = IPMI_LANPARM_VLAN_ID;
1536 else {
1537 lanc->curr_parm++;
1538 lanc->curr_sel = 0;
1539 }
1540 break;
1541
1542 case IPMI_LANPARM_DEST_TYPE:
1543 lanc->curr_sel++;
1544 if (lanc->curr_sel >= lanc->num_alert_destinations) {
1545 lanc->curr_parm++;
1546 lanc->curr_sel = 0;
1547 }
1548 break;
1549
1550 case IPMI_LANPARM_DEST_ADDR:
1551 lanc->curr_sel++;
1552 if (lanc->curr_sel >= lanc->num_alert_destinations) {
1553 lanc->curr_parm = IPMI_LANPARM_VLAN_ID;
1554 lanc->curr_sel = 0;
1555 }
1556 break;
1557
1558 case IPMI_LANPARM_NUM_CIPHER_SUITE_ENTRIES:
1559 lanc->curr_parm++;
1560 if (lanc->num_cipher_suites == 0) {
1561 if (lanc->num_alert_destinations == 0)
1562 goto done;
1563 lanc->curr_parm = IPMI_LANPARM_DEST_VLAN_TAG;
1564 lanc->curr_sel = 0;
1565 }
1566 break;
1567
1568 case IPMI_LANPARM_CIPHER_SUITE_ENTRY_PRIV:
1569 if (lanc->num_alert_destinations == 0)
1570 goto done;
1571 else {
1572 lanc->curr_parm++;
1573 lanc->curr_sel = 0;
1574 }
1575 break;
1576
1577 case IPMI_LANPARM_DEST_VLAN_TAG:
1578 if (!lanc->vlan_tag_supported)
1579 goto done;
1580 if ((data[1] & 0xf) != lanc->curr_sel) {
1581 /* Yikes, wrong selector came back! */
1582 ipmi_log(IPMI_LOG_ERR_INFO,
1583 "lanparm.c(got_parm): "
1584 "Error fetching dest type %d,"
1585 " wrong selector came back, expecting %d, was %d",
1586 lanc->curr_parm, lanc->curr_sel, data[1] & 0xf);
1587 err = EINVAL;
1588 goto done;
1589 }
1590 lanc->curr_sel++;
1591 if (lanc->curr_sel >= lanc->num_alert_destinations)
1592 goto done;
1593 break;
1594
1595 default:
1596 lanc->curr_parm++;
1597 }
1598
1599 lp = &(lanparms[lanc->curr_parm]);
1600 if (!lp->valid)
1601 goto next_parm;
1602
1603 err = ipmi_lanparm_get_parm(lanparm, lanc->curr_parm, lanc->curr_sel, 0,
1604 got_parm, lanc);
1605 if (err)
1606 goto done;
1607
1608 return;
1609
1610 done:
1611 if (err) {
1612 unsigned char data[1];
1613
1614 ipmi_log(IPMI_LOG_ERR_INFO,
1615 "lanparm.c(got_parm): Error trying to get parm %d: %x",
1616 lanc->curr_parm, err);
1617 lanc->err = err;
1618 /* Clear the lock */
1619 data[0] = 0;
1620 err = ipmi_lanparm_set_parm(lanparm, 0, data, 1,
1621 err_lock_cleared, lanc);
1622 if (err) {
1623 ipmi_lan_free_config(lanc);
1624 ipmi_log(IPMI_LOG_ERR_INFO,
1625 "lanparm.c(got_parm): Error trying to clear lock: %x",
1626 err);
1627 lanc->done(lanparm, lanc->err, NULL, lanc->cb_data);
1628 ipmi_lan_free_config(lanc);
1629 lanparm->locked = 0;
1630 lanparm_put(lanparm);
1631 }
1632 } else {
1633 lanc->done(lanparm, 0, lanc, lanc->cb_data);
1634 lanparm_put(lanparm);
1635 }
1636 }
1637
1638 static void
lock_done(ipmi_lanparm_t * lanparm,int err,void * cb_data)1639 lock_done(ipmi_lanparm_t *lanparm,
1640 int err,
1641 void *cb_data)
1642 {
1643 ipmi_lan_config_t *lanc = cb_data;
1644 int rv;
1645
1646 if (err == IPMI_IPMI_ERR_VAL(0x80)) {
1647 /* Lock is not supported, just mark it and go on. */
1648 lanc->lock_supported = 0;
1649 } else if (err == IPMI_IPMI_ERR_VAL(0x81)) {
1650 /* Someone else has the lock, return EAGAIN. */
1651 lanc->done(lanparm, EAGAIN, NULL, lanc->cb_data);
1652 ipmi_lan_free_config(lanc);
1653 lanparm_put(lanparm);
1654 return;
1655 } else if (err) {
1656 ipmi_log(IPMI_LOG_ERR_INFO,
1657 "lanparm.c(lock_done): Error trying to lock the LAN"
1658 " parms: %x",
1659 err);
1660 lanc->done(lanparm, err, NULL, lanc->cb_data);
1661 ipmi_lan_free_config(lanc);
1662 lanparm_put(lanparm);
1663 return;
1664 } else {
1665 lanc->lan_locked = 1;
1666 lanparm->locked = 1;
1667 }
1668
1669 rv = ipmi_lanparm_get_parm(lanparm, lanc->curr_parm, lanc->curr_sel, 0,
1670 got_parm, lanc);
1671 if (rv) {
1672 unsigned char data[1];
1673 ipmi_log(IPMI_LOG_ERR_INFO,
1674 "lanparm.c(lock_done): Error trying to get parms: %x",
1675 err);
1676
1677 lanc->err = rv;
1678 /* Clear the lock */
1679 data[0] = 0;
1680 rv = ipmi_lanparm_set_parm(lanparm, 0, data, 1,
1681 err_lock_cleared, lanc);
1682 if (rv) {
1683 ipmi_log(IPMI_LOG_ERR_INFO,
1684 "lanparm.c(lock_done): Error trying to clear lock: %x",
1685 err);
1686 lanc->done(lanparm, lanc->err, NULL, lanc->cb_data);
1687 ipmi_lan_free_config(lanc);
1688 lanparm->locked = 0;
1689 lanparm_put(lanparm);
1690 }
1691 }
1692 }
1693
ipmi_lan_get_config(ipmi_lanparm_t * lanparm,ipmi_lan_get_config_cb done,void * cb_data)1694 int ipmi_lan_get_config(ipmi_lanparm_t *lanparm,
1695 ipmi_lan_get_config_cb done,
1696 void *cb_data)
1697 {
1698 ipmi_lan_config_t *lanc;
1699 int rv;
1700 unsigned char data[1];
1701
1702 lanc = ipmi_mem_alloc(sizeof(*lanc));
1703 if (!lanc)
1704 return ENOMEM;
1705 memset(lanc, 0, sizeof(*lanc));
1706
1707 lanc->curr_parm = 1;
1708 lanc->curr_sel = 0;
1709 lanc->done = done;
1710 lanc->cb_data = cb_data;
1711 lanc->my_lan = lanparm;
1712 lanc->lock_supported = 1; /* Assume it works */
1713
1714 lanparm_get(lanparm);
1715
1716 /* First grab the lock */
1717 data[0] = 1; /* Set in progress. */
1718 rv = ipmi_lanparm_set_parm(lanparm, 0, data, 1, lock_done, lanc);
1719 if (rv) {
1720 ipmi_lan_free_config(lanc);
1721 lanparm_put(lanparm);
1722 }
1723
1724 return rv;
1725 }
1726
1727 static void
set_clear(ipmi_lanparm_t * lanparm,int err,void * cb_data)1728 set_clear(ipmi_lanparm_t *lanparm,
1729 int err,
1730 void *cb_data)
1731 {
1732 ipmi_lan_config_t *lanc = cb_data;
1733
1734 if (lanc->err)
1735 err = lanc->err;
1736 if (lanc->set_done)
1737 lanc->set_done(lanparm, err, lanc->cb_data);
1738 ipmi_lan_free_config(lanc);
1739 lanparm->locked = 0;
1740 lanparm_put(lanparm);
1741 }
1742
1743 static void
commit_done(ipmi_lanparm_t * lanparm,int err,void * cb_data)1744 commit_done(ipmi_lanparm_t *lanparm,
1745 int err,
1746 void *cb_data)
1747 {
1748 ipmi_lan_config_t *lanc = cb_data;
1749 unsigned char data[1];
1750 int rv;
1751
1752 /* Note that we ignore the error. The commit done is optional,
1753 and must return an error if it is optional, so we just ignore
1754 the error and clear the field here. */
1755
1756 /* Commit is done. The IPMI spec says that it goes into the
1757 set-in-progress state after this, so we need to clear it. */
1758
1759 data[0] = 0;
1760 rv = ipmi_lanparm_set_parm(lanparm, 0, data, 1, set_clear, lanc);
1761 if (rv) {
1762 ipmi_log(IPMI_LOG_WARNING,
1763 "lanparm.c(commit_done): Error trying to clear the set in"
1764 " progress: %x",
1765 rv);
1766 set_clear(lanparm, err, lanc);
1767 }
1768 }
1769
1770 static void
set_done(ipmi_lanparm_t * lanparm,int err,void * cb_data)1771 set_done(ipmi_lanparm_t *lanparm,
1772 int err,
1773 void *cb_data)
1774 {
1775 ipmi_lan_config_t *lanc = cb_data;
1776 unsigned char data[MAX_IPMI_DATA_SIZE] = { 0, 0 };
1777 lanparms_t *lp = &(lanparms[lanc->curr_parm]);
1778
1779 if (err == IPMI_IPMI_ERR_VAL(0x82)) {
1780 /* We attempted to write a read-only parameter that is not
1781 marked by the spec as read-only. Just ignore it. */
1782 err = 0;
1783 }
1784
1785 if (err) {
1786 ipmi_log(IPMI_LOG_ERR_INFO,
1787 "lanparm.c(set_done): Error setting lan parm %d sel %d: %x",
1788 lanc->curr_parm, lanc->curr_sel, err);
1789 goto done;
1790 }
1791
1792 next_parm:
1793 switch (lanc->curr_parm) {
1794 /*
1795 * Set the IP address source before the IP address itself. Some
1796 * BMCs are picky and won't set the IP address if the address
1797 * source is not static.
1798 */
1799 case IPMI_LANPARM_AUTH_TYPE_ENABLES:
1800 lanc->curr_parm = IPMI_LANPARM_IP_ADDRESS_SRC;
1801 break;
1802 case IPMI_LANPARM_IP_ADDRESS_SRC:
1803 lanc->curr_parm = IPMI_LANPARM_IP_ADDRESS;
1804 break;
1805 case IPMI_LANPARM_IP_ADDRESS:
1806 lanc->curr_parm = IPMI_LANPARM_MAC_ADDRESS;
1807 break;
1808
1809 case IPMI_LANPARM_NUM_DESTINATIONS:
1810 lanc->curr_parm++;
1811 if (lanc->num_alert_destinations == 0) {
1812 lanc->curr_parm = IPMI_LANPARM_VLAN_ID;
1813 goto next_parm;
1814 }
1815 lanc->curr_sel = 0;
1816 data[0] = lanc->curr_sel;
1817 break;
1818
1819 case IPMI_LANPARM_DEST_TYPE:
1820 lanc->curr_sel++;
1821 if (lanc->curr_sel >= lanc->num_alert_destinations) {
1822 lanc->curr_parm++;
1823 lanc->curr_sel = 0;
1824 }
1825 data[0] = lanc->curr_sel;
1826 break;
1827
1828 case IPMI_LANPARM_DEST_ADDR:
1829 lanc->curr_sel++;
1830 if (lanc->curr_sel >= lanc->num_alert_destinations) {
1831 lanc->curr_parm++;
1832 lanc->curr_sel = 0;
1833 }
1834 data[0] = lanc->curr_sel;
1835 break;
1836
1837 case IPMI_LANPARM_CIPHER_SUITE_ENTRY_PRIV:
1838 lanc->curr_parm++;
1839 if (lanc->num_alert_destinations == 0)
1840 goto done;
1841 lanc->curr_sel = 0;
1842 data[0] = lanc->curr_sel;
1843 break;
1844
1845 case IPMI_LANPARM_DEST_VLAN_TAG:
1846 lanc->curr_sel++;
1847 if (lanc->curr_sel >= lanc->num_alert_destinations)
1848 goto done;
1849 data[0] = lanc->curr_sel;
1850 break;
1851
1852 default:
1853 lanc->curr_parm++;
1854 }
1855
1856 lp = &(lanparms[lanc->curr_parm]);
1857 if ((!lp->valid) || (!lp->set_handler)
1858 || (lp->optional_offset
1859 && !(((unsigned char *) lanc)[lp->optional_offset])))
1860 {
1861 /* The parameter is read-only or not supported, just go on. */
1862 goto next_parm;
1863 }
1864
1865 if ((lanc->ip_addr_source == IPMI_LANPARM_IP_ADDR_SRC_DHCP) &&
1866 (lanc->curr_parm == IPMI_LANPARM_IP_ADDRESS ||
1867 lanc->curr_parm == IPMI_LANPARM_SUBNET_MASK ||
1868 lanc->curr_parm == IPMI_LANPARM_DEFAULT_GATEWAY_ADDR ||
1869 lanc->curr_parm == IPMI_LANPARM_BACKUP_GATEWAY_ADDR))
1870 {
1871 /*
1872 * Don't set the fields that come from DHCP if the address
1873 * source is DHCP. Some BMCs are picky about this and will
1874 * error if you try to set these fields and the address source
1875 * is DHCP.
1876 */
1877 goto next_parm;
1878 }
1879
1880
1881 lp->set_handler(lanc, lp, data);
1882 err = ipmi_lanparm_set_parm(lanparm, lanc->curr_parm,
1883 data, lp->length, set_done, lanc);
1884 if (err)
1885 goto done;
1886
1887 return;
1888
1889 done:
1890 if (!lanc->lock_supported) {
1891 /* No lock support, just finish the operation. */
1892 set_clear(lanparm, err, lanc);
1893 return;
1894 }
1895 else if (err) {
1896 data[0] = 0; /* Don't commit the parameters. */
1897 lanc->err = err;
1898 err = ipmi_lanparm_set_parm(lanparm, 0, data, 1, set_clear, lanc);
1899 } else {
1900 data[0] = 2; /* Commit the parameters. */
1901 err = ipmi_lanparm_set_parm(lanparm, 0, data, 1, commit_done, lanc);
1902 }
1903 if (err) {
1904 ipmi_log(IPMI_LOG_WARNING,
1905 "lanparm.c(set_done): Error trying to clear the set in"
1906 " progress: %x",
1907 err);
1908 set_clear(lanparm, err, lanc);
1909 }
1910 }
1911
1912 int
ipmi_lan_set_config(ipmi_lanparm_t * lanparm,ipmi_lan_config_t * olanc,ipmi_lanparm_done_cb done,void * cb_data)1913 ipmi_lan_set_config(ipmi_lanparm_t *lanparm,
1914 ipmi_lan_config_t *olanc,
1915 ipmi_lanparm_done_cb done,
1916 void *cb_data)
1917 {
1918 ipmi_lan_config_t *lanc;
1919 unsigned char data[MAX_IPMI_DATA_SIZE];
1920 lanparms_t *lp;
1921 int rv;
1922
1923 if (olanc->my_lan != lanparm)
1924 return EINVAL;
1925
1926 if (!olanc->lan_locked)
1927 return EINVAL;
1928
1929 lanc = ipmi_mem_alloc(sizeof(*lanc));
1930 if (!lanc)
1931 return ENOMEM;
1932
1933 *lanc = *olanc;
1934 lanc->alert_dest_type = NULL;
1935 lanc->alert_dest_addr = NULL;
1936 lanc->err = 0;
1937 lanc->lan_locked = 0; /* Set this here, since we will unlock it,
1938 but we don't want the free operation to
1939 attempt an unlock */
1940
1941 if (lanc->num_alert_destinations) {
1942 lanc->alert_dest_type
1943 = ipmi_mem_alloc(sizeof(alert_dest_type_t)
1944 * lanc->num_alert_destinations);
1945 if (!lanc->alert_dest_type) {
1946 rv = ENOMEM;
1947 goto out;
1948 }
1949 memcpy(lanc->alert_dest_type, olanc->alert_dest_type,
1950 sizeof(alert_dest_type_t) * lanc->num_alert_destinations);
1951
1952 lanc->alert_dest_addr
1953 = ipmi_mem_alloc(sizeof(alert_dest_addr_t)
1954 * lanc->num_alert_destinations);
1955 if (!lanc->alert_dest_addr) {
1956 rv = ENOMEM;
1957 goto out;
1958 }
1959 memcpy(lanc->alert_dest_addr, olanc->alert_dest_addr,
1960 sizeof(alert_dest_addr_t) * lanc->num_alert_destinations);
1961 }
1962
1963 lanc->curr_parm = 2;
1964 lanc->curr_sel = 0;
1965 lanc->set_done = done;
1966 lanc->cb_data = cb_data;
1967
1968 /* Parm 2 is known good for writing. */
1969 lp = &(lanparms[lanc->curr_parm]);
1970 lp->set_handler(lanc, lp, data);
1971 rv = ipmi_lanparm_set_parm(lanparm, lanc->curr_parm,
1972 data, lp->length, set_done, lanc);
1973 out:
1974 if (rv) {
1975 ipmi_lan_free_config(lanc);
1976 } else {
1977 /* The old config no longer holds the lock. */
1978 olanc->lan_locked = 0;
1979 lanparm_get(lanparm);
1980 }
1981 return rv;
1982 }
1983
1984 typedef struct clear_lock_s
1985 {
1986 ipmi_lanparm_done_cb done;
1987 void *cb_data;
1988
1989 } clear_lock_t;
1990
1991 static void
lock_cleared(ipmi_lanparm_t * lanparm,int err,void * cb_data)1992 lock_cleared(ipmi_lanparm_t *lanparm,
1993 int err,
1994 void *cb_data)
1995 {
1996 clear_lock_t *cl = cb_data;
1997
1998 cl->done(lanparm, err, cl->cb_data);
1999
2000 ipmi_mem_free(cl);
2001 lanparm->locked = 0;
2002 lanparm_put(lanparm);
2003 }
2004
2005 int
ipmi_lan_clear_lock(ipmi_lanparm_t * lanparm,ipmi_lan_config_t * lanc,ipmi_lanparm_done_cb done,void * cb_data)2006 ipmi_lan_clear_lock(ipmi_lanparm_t *lanparm,
2007 ipmi_lan_config_t *lanc,
2008 ipmi_lanparm_done_cb done,
2009 void *cb_data)
2010 {
2011 unsigned char data[1];
2012 int rv;
2013 clear_lock_t *cl;
2014
2015 if (lanc) {
2016 if (lanc->my_lan != lanparm)
2017 return EINVAL;
2018
2019 if (!lanc->lan_locked)
2020 return EINVAL;
2021 }
2022
2023 cl = ipmi_mem_alloc(sizeof(*cl));
2024 if (!cl)
2025 return ENOMEM;
2026 cl->done = done;
2027 cl->cb_data = cb_data;
2028
2029 data[0] = 0; /* Clear the lock. */
2030 rv = ipmi_lanparm_set_parm(lanparm, 0, data, 1, lock_cleared, cl);
2031 if (rv) {
2032 ipmi_mem_free(cl);
2033 } else {
2034 if (lanc)
2035 lanc->lan_locked = 0;
2036 lanparm_get(lanparm);
2037 }
2038
2039 return rv;
2040 }
2041
2042 void
ipmi_lan_free_config(ipmi_lan_config_t * lanc)2043 ipmi_lan_free_config(ipmi_lan_config_t *lanc)
2044 {
2045 if (lanc->alert_dest_type != NULL)
2046 ipmi_mem_free(lanc->alert_dest_type);
2047 if (lanc->alert_dest_addr != NULL)
2048 ipmi_mem_free(lanc->alert_dest_addr);
2049 ipmi_mem_free(lanc);
2050 }
2051
2052 #define AUTH_SUP(n) \
2053 unsigned int \
2054 ipmi_lanconfig_get_support_auth_ ## n(ipmi_lan_config_t *lanc) \
2055 { \
2056 return lanc->auth_support.n; \
2057 }
2058
2059 AUTH_SUP(oem)
2060 AUTH_SUP(straight)
2061 AUTH_SUP(md5)
2062 AUTH_SUP(md2)
2063 AUTH_SUP(none)
2064
2065 #define AUTH_ENAB(n) \
2066 int \
2067 ipmi_lanconfig_get_enable_auth_ ## n(ipmi_lan_config_t *lanc, \
2068 unsigned int user, \
2069 unsigned int *val) \
2070 { \
2071 if (user >= 5) \
2072 return EINVAL; \
2073 *val = lanc->auth_enable[user].n; \
2074 return 0; \
2075 } \
2076 int \
2077 ipmi_lanconfig_set_enable_auth_ ## n(ipmi_lan_config_t *lanc, \
2078 unsigned int user, \
2079 unsigned int val) \
2080 { \
2081 if (user >= 5) \
2082 return EINVAL; \
2083 lanc->auth_enable[user].n = (val != 0); \
2084 return 0; \
2085 }
2086
2087 AUTH_ENAB(oem)
2088 AUTH_ENAB(straight)
2089 AUTH_ENAB(md5)
2090 AUTH_ENAB(md2)
2091 AUTH_ENAB(none)
2092
2093 #define LP_INT_PARM(n) \
2094 unsigned int \
2095 ipmi_lanconfig_get_ ## n(ipmi_lan_config_t *lanc) \
2096 { \
2097 return lanc->n; \
2098 } \
2099 int \
2100 ipmi_lanconfig_set_ ## n(ipmi_lan_config_t *lanc, \
2101 unsigned int val) \
2102 { \
2103 lanc->n = val; \
2104 return 0; \
2105 }
2106
2107 #define LP_ARRAY_PARM(n, l) \
2108 int \
2109 ipmi_lanconfig_get_ ## n(ipmi_lan_config_t *lanc, \
2110 unsigned char *data, \
2111 unsigned int *data_len) \
2112 { \
2113 if (*data_len < l) { \
2114 *data_len = l; \
2115 return EBADF; \
2116 } \
2117 memcpy(data, lanc->n, l); \
2118 *data_len = l; \
2119 return 0; \
2120 } \
2121 int \
2122 ipmi_lanconfig_set_ ## n(ipmi_lan_config_t *lanc, \
2123 unsigned char *data, \
2124 unsigned int data_len) \
2125 { \
2126 if (data_len != l) \
2127 return EBADF; \
2128 memcpy(lanc->n, data, l); \
2129 return 0; \
2130 }
2131
2132 LP_ARRAY_PARM(ip_addr, 4)
2133 LP_INT_PARM(ip_addr_source);
2134 LP_ARRAY_PARM(mac_addr, 6)
2135 LP_ARRAY_PARM(subnet_mask, 4)
2136 LP_ARRAY_PARM(default_gateway_ip_addr, 4)
2137 LP_ARRAY_PARM(community_string, 18)
2138
2139 #define LP_ARRAY_PARM_SUP(n, l) \
2140 int \
2141 ipmi_lanconfig_get_ ## n(ipmi_lan_config_t *lanc, \
2142 unsigned char *data, \
2143 unsigned int *data_len) \
2144 { \
2145 if (! lanc->n ## _supported) \
2146 return ENOSYS; \
2147 if (*data_len < l) { \
2148 *data_len = l; \
2149 return EBADF; \
2150 } \
2151 memcpy(data, lanc->n, l); \
2152 *data_len = l; \
2153 return 0; \
2154 } \
2155 int \
2156 ipmi_lanconfig_set_ ## n(ipmi_lan_config_t *lanc, \
2157 unsigned char *data, \
2158 unsigned int data_len) \
2159 { \
2160 if (! lanc->n ## _supported) \
2161 return ENOSYS; \
2162 if (data_len != l) \
2163 return EBADF; \
2164 memcpy(lanc->n, data, l); \
2165 return 0; \
2166 }
2167
2168 LP_ARRAY_PARM_SUP(primary_rmcp_port, 2)
2169 LP_ARRAY_PARM_SUP(secondary_rmcp_port, 2)
2170 LP_ARRAY_PARM_SUP(default_gateway_mac_addr, 6)
2171 LP_ARRAY_PARM_SUP(backup_gateway_ip_addr, 4)
2172 LP_ARRAY_PARM_SUP(backup_gateway_mac_addr, 6)
2173
2174 int
ipmi_lanconfig_get_port_rmcp_primary(ipmi_lan_config_t * lanc,unsigned int * val)2175 ipmi_lanconfig_get_port_rmcp_primary(ipmi_lan_config_t *lanc,
2176 unsigned int *val)
2177 {
2178 uint16_t data;
2179 int rv;
2180 unsigned int len = 2;
2181
2182 rv = ipmi_lanconfig_get_primary_rmcp_port(lanc, (unsigned char *) &data,
2183 &len);
2184 if (rv)
2185 return rv;
2186 *val = ntohs(data);
2187 return 0;
2188 }
2189
2190 int
ipmi_lanconfig_set_port_rmcp_primary(ipmi_lan_config_t * lanc,unsigned int val)2191 ipmi_lanconfig_set_port_rmcp_primary(ipmi_lan_config_t *lanc,
2192 unsigned int val)
2193 {
2194 uint16_t data;
2195 int rv;
2196
2197 data = htons(val);
2198 rv = ipmi_lanconfig_set_primary_rmcp_port(lanc, (unsigned char *) &data, 2);
2199 return rv;
2200 }
2201
2202 int
ipmi_lanconfig_get_port_rmcp_secondary(ipmi_lan_config_t * lanc,unsigned int * val)2203 ipmi_lanconfig_get_port_rmcp_secondary(ipmi_lan_config_t *lanc,
2204 unsigned int *val)
2205 {
2206 uint16_t data;
2207 int rv;
2208 unsigned int len = 2;
2209
2210 rv = ipmi_lanconfig_get_secondary_rmcp_port(lanc, (unsigned char *) &data,
2211 &len);
2212 if (rv)
2213 return rv;
2214 *val = ntohs(data);
2215 return 0;
2216 }
2217
2218 int
ipmi_lanconfig_set_port_rmcp_secondary(ipmi_lan_config_t * lanc,unsigned int val)2219 ipmi_lanconfig_set_port_rmcp_secondary(ipmi_lan_config_t *lanc,
2220 unsigned int val)
2221 {
2222 uint16_t data;
2223 int rv;
2224
2225 data = htons(val);
2226 rv = ipmi_lanconfig_set_secondary_rmcp_port(lanc, (unsigned char *) &data,
2227 2);
2228 return rv;
2229 }
2230
2231
2232 #define LP_INT_PARM_SUP(n, s) \
2233 int \
2234 ipmi_lanconfig_get_ ## n(ipmi_lan_config_t *lanc, \
2235 unsigned int *data) \
2236 { \
2237 if (! lanc->s) \
2238 return ENOSYS; \
2239 *data = lanc->n; \
2240 return 0; \
2241 } \
2242 int \
2243 ipmi_lanconfig_set_ ## n(ipmi_lan_config_t *lanc, \
2244 unsigned int data) \
2245 { \
2246 if (! lanc->s) \
2247 return ENOSYS; \
2248 lanc->n = data; \
2249 return 0; \
2250 }
2251
2252 LP_INT_PARM_SUP(ipv4_ttl, ipv4_header_parms_supported);
2253 LP_INT_PARM_SUP(ipv4_flags, ipv4_header_parms_supported);
2254 LP_INT_PARM_SUP(ipv4_precedence, ipv4_header_parms_supported);
2255 LP_INT_PARM_SUP(ipv4_tos, ipv4_header_parms_supported);
LP_INT_PARM_SUP(bmc_generated_arps,arp_control_supported)2256 LP_INT_PARM_SUP(bmc_generated_arps, arp_control_supported)
2257 LP_INT_PARM_SUP(bmc_generated_garps, arp_control_supported)
2258 LP_INT_PARM_SUP(garp_interval, garp_interval_supported)
2259
2260 LP_INT_PARM_SUP(vlan_id, vlan_id_supported)
2261 LP_INT_PARM_SUP(vlan_id_enable, vlan_id_supported)
2262
2263 LP_INT_PARM_SUP(vlan_priority, vlan_priority_supported)
2264
2265 unsigned int
2266 ipmi_lanconfig_get_num_alert_destinations(ipmi_lan_config_t *lanc)
2267 {
2268 return lanc->num_alert_destinations;
2269 }
2270
2271 #define LP_INT_TAB(s, n) \
2272 int \
2273 ipmi_lanconfig_get_## n(ipmi_lan_config_t *lanc, \
2274 unsigned int set, \
2275 unsigned int *val) \
2276 { \
2277 if (set > lanc->num_alert_destinations) \
2278 return EINVAL; \
2279 *val = lanc->s[set].n; \
2280 return 0; \
2281 } \
2282 int \
2283 ipmi_lanconfig_set_## n(ipmi_lan_config_t *lanc, \
2284 unsigned int set, \
2285 unsigned int val) \
2286 { \
2287 if (set > lanc->num_alert_destinations) \
2288 return EINVAL; \
2289 lanc->s[set].n = val; \
2290 return 0; \
2291 }
2292
2293 #define LP_INT_TAB_SUP(s, n, p) \
2294 int \
2295 ipmi_lanconfig_get_## n(ipmi_lan_config_t *lanc, \
2296 unsigned int set, \
2297 unsigned int *val) \
2298 { \
2299 if (! lanc->p) \
2300 return ENOSYS; \
2301 if (set > lanc->num_alert_destinations) \
2302 return EINVAL; \
2303 *val = lanc->s[set].n; \
2304 return 0; \
2305 } \
2306 int \
2307 ipmi_lanconfig_set_## n(ipmi_lan_config_t *lanc, \
2308 unsigned int set, \
2309 unsigned int val) \
2310 { \
2311 if (! lanc->p) \
2312 return ENOSYS; \
2313 if (set > lanc->num_alert_destinations) \
2314 return EINVAL; \
2315 lanc->s[set].n = val; \
2316 return 0; \
2317 }
2318
2319 #define LP_ARRAY_TAB(s, n, l) \
2320 int \
2321 ipmi_lanconfig_get_## n(ipmi_lan_config_t *lanc, \
2322 unsigned int set, \
2323 unsigned char *data, \
2324 unsigned int *data_len) \
2325 { \
2326 if (set > lanc->num_alert_destinations) \
2327 return EINVAL; \
2328 if (*data_len < l) { \
2329 *data_len = l; \
2330 return EBADF; \
2331 } \
2332 memcpy(data, lanc->s[set].n, l); \
2333 *data_len = l; \
2334 return 0; \
2335 } \
2336 int \
2337 ipmi_lanconfig_set_## n(ipmi_lan_config_t *lanc, \
2338 unsigned int set, \
2339 unsigned char *data, \
2340 unsigned int data_len) \
2341 { \
2342 if (set > lanc->num_alert_destinations) \
2343 return EINVAL; \
2344 if (data_len != l) \
2345 return EBADF; \
2346 memcpy(lanc->s[set].n, data, l); \
2347 return 0; \
2348 }
2349
LP_INT_TAB(alert_dest_type,alert_ack)2350 LP_INT_TAB(alert_dest_type, alert_ack)
2351 LP_INT_TAB(alert_dest_type, dest_type)
2352 LP_INT_TAB(alert_dest_type, alert_retry_interval)
2353 LP_INT_TAB(alert_dest_type, max_alert_retries)
2354
2355 LP_INT_TAB(alert_dest_addr, dest_format)
2356 LP_INT_TAB(alert_dest_addr, gw_to_use)
2357 LP_ARRAY_TAB(alert_dest_addr, dest_ip_addr, 4)
2358 LP_ARRAY_TAB(alert_dest_addr, dest_mac_addr, 6)
2359
2360 LP_INT_TAB_SUP(alert_dest_addr, dest_vlan_tag_type, vlan_tag_supported)
2361 LP_INT_TAB_SUP(alert_dest_addr, dest_vlan_tag, vlan_tag_supported)
2362
2363 unsigned int
2364 ipmi_lanconfig_get_num_cipher_suites(ipmi_lan_config_t *lanc)
2365 {
2366 return lanc->num_cipher_suites;
2367 }
2368
2369 int
ipmi_lanconfig_get_cipher_suite_entry(ipmi_lan_config_t * lanc,unsigned int entry,unsigned int * val)2370 ipmi_lanconfig_get_cipher_suite_entry(ipmi_lan_config_t *lanc,
2371 unsigned int entry,
2372 unsigned int *val)
2373 {
2374 if (entry >= lanc->num_cipher_suites)
2375 return EINVAL;
2376 *val = lanc->cipher_suite_entries[entry];
2377 return 0;
2378 }
2379
2380 int
ipmi_lanconfig_set_cipher_suite_entry(ipmi_lan_config_t * lanc,unsigned int entry,unsigned int val)2381 ipmi_lanconfig_set_cipher_suite_entry(ipmi_lan_config_t *lanc,
2382 unsigned int entry,
2383 unsigned int val)
2384 {
2385 if (! lanc->max_priv_for_cipher_suite_supported)
2386 return ENOSYS;
2387 if (entry >= lanc->num_cipher_suites)
2388 return EINVAL;
2389 lanc->cipher_suite_entries[entry] = val;
2390 return 0;
2391 }
2392
2393 int
ipmi_lanconfig_get_max_priv_for_cipher_suite(ipmi_lan_config_t * lanc,unsigned int entry,unsigned int * val)2394 ipmi_lanconfig_get_max_priv_for_cipher_suite(ipmi_lan_config_t *lanc,
2395 unsigned int entry,
2396 unsigned int *val)
2397 {
2398 if (! lanc->max_priv_for_cipher_suite_supported)
2399 return ENOSYS;
2400 if (entry >= lanc->num_cipher_suites)
2401 return EINVAL;
2402 *val = lanc->max_priv_for_cipher_suite[entry];
2403 return 0;
2404 }
2405
2406 int
ipmi_lanconfig_set_max_priv_for_cipher_suite(ipmi_lan_config_t * lanc,unsigned int entry,unsigned int val)2407 ipmi_lanconfig_set_max_priv_for_cipher_suite(ipmi_lan_config_t *lanc,
2408 unsigned int entry,
2409 unsigned int val)
2410 {
2411 if (entry >= lanc->num_cipher_suites)
2412 return EINVAL;
2413 lanc->max_priv_for_cipher_suite[entry] = val;
2414 return 0;
2415 }
2416
2417
2418 typedef struct lanparm_gendata_s
2419 {
2420 enum ipmi_lanconf_val_type_e datatype;
2421 char *fname;
2422
2423 union {
2424 struct {
2425 unsigned int (*gval)(ipmi_lan_config_t *lanc);
2426 int (*gval_v)(ipmi_lan_config_t *lanc, unsigned int *val);
2427 int (*gval_iv)(ipmi_lan_config_t *lanc, unsigned int idx,
2428 unsigned int *val);
2429 int (*sval)(ipmi_lan_config_t *lanc, unsigned int val);
2430 int (*sval_v)(ipmi_lan_config_t *lanc, unsigned int val);
2431 int (*sval_iv)(ipmi_lan_config_t *lanc, unsigned int idx,
2432 unsigned int val);
2433 } ival;
2434 struct {
2435 int (*gval_v)(ipmi_lan_config_t *lanc, unsigned char *data,
2436 unsigned int *data_len);
2437 int (*gval_iv)(ipmi_lan_config_t *lanc, unsigned int idx,
2438 unsigned char *data, unsigned int *data_len);
2439 int (*sval_v)(ipmi_lan_config_t *lanc, unsigned char *data,
2440 unsigned int data_len);
2441 int (*sval_iv)(ipmi_lan_config_t *lanc, unsigned int idx,
2442 unsigned char *data, unsigned int data_len);
2443 } dval;
2444 } u;
2445 unsigned int (*iv_cnt)(ipmi_lan_config_t *lanc);
2446 } lanparm_gendata_t;
2447
ret_user_cnt(ipmi_lan_config_t * lanc)2448 static unsigned int ret_user_cnt(ipmi_lan_config_t *lanc)
2449 {
2450 return 5;
2451 }
2452
2453 #define F_BOOLR(name) \
2454 { .datatype = IPMI_LANCONFIG_BOOL, .fname = #name, \
2455 .u = { .ival = { .gval = ipmi_lanconfig_get_ ## name }}}
2456 #define F_INTR(name) \
2457 { .datatype = IPMI_LANCONFIG_INT, .fname = #name, \
2458 .u = { .ival = { .gval = ipmi_lanconfig_get_ ## name }}}
2459 #define F_INT(name) \
2460 { .datatype = IPMI_LANCONFIG_INT, .fname = #name, \
2461 .u = { .ival = { .gval = ipmi_lanconfig_get_ ## name, \
2462 .sval = ipmi_lanconfig_set_ ## name }}}
2463 #define F_INTV(name) \
2464 { .datatype = IPMI_LANCONFIG_INT, .fname = #name, \
2465 .u = { .ival = { .gval_v = ipmi_lanconfig_get_ ## name, \
2466 .sval_v = ipmi_lanconfig_set_ ## name }}}
2467 #define F_INTIV(name, gcnt) \
2468 { .datatype = IPMI_LANCONFIG_INT, .fname = #name, \
2469 .u = { .ival = { .gval_iv = ipmi_lanconfig_get_ ## name, \
2470 .sval_iv = ipmi_lanconfig_set_ ## name }}, \
2471 .iv_cnt = gcnt }
2472 #define F_BOOLV(name) \
2473 { .datatype = IPMI_LANCONFIG_BOOL, .fname = #name, \
2474 .u = { .ival = { .gval_v = ipmi_lanconfig_get_ ## name, \
2475 .sval_v = ipmi_lanconfig_set_ ## name }}}
2476 #define F_BOOLIV(name, gcnt) \
2477 { .datatype = IPMI_LANCONFIG_BOOL, .fname = #name, \
2478 .u = { .ival = { .gval_iv = ipmi_lanconfig_get_ ## name, \
2479 .sval_iv = ipmi_lanconfig_set_ ## name }}, \
2480 .iv_cnt = gcnt }
2481 #define F_IP(name) \
2482 { .datatype = IPMI_LANCONFIG_IP, .fname = #name, \
2483 .u = { .dval = { .gval_v = ipmi_lanconfig_get_ ## name, \
2484 .sval_v = ipmi_lanconfig_set_ ## name }}}
2485 #define F_MAC(name) \
2486 { .datatype = IPMI_LANCONFIG_MAC, .fname = #name, \
2487 .u = { .dval = { .gval_v = ipmi_lanconfig_get_ ## name, \
2488 .sval_v = ipmi_lanconfig_set_ ## name }}}
2489 #define F_IPIV(name, gcnt) \
2490 { .datatype = IPMI_LANCONFIG_IP, .fname = #name, \
2491 .u = { .dval = { .gval_iv = ipmi_lanconfig_get_ ## name, \
2492 .sval_iv = ipmi_lanconfig_set_ ## name }}, \
2493 .iv_cnt = gcnt }
2494 #define F_MACIV(name, gcnt) \
2495 { .datatype = IPMI_LANCONFIG_MAC, .fname = #name, \
2496 .u = { .dval = { .gval_iv = ipmi_lanconfig_get_ ## name, \
2497 .sval_iv = ipmi_lanconfig_set_ ## name }}, \
2498 .iv_cnt = gcnt }
2499 #define F_DATA(name) \
2500 { .datatype = IPMI_LANCONFIG_DATA, .fname = #name, \
2501 .u = { .dval = { .gval_v = ipmi_lanconfig_get_ ## name, \
2502 .sval_v = ipmi_lanconfig_set_ ## name }}}
2503
2504 static lanparm_gendata_t gdata[] =
2505 {
2506 F_BOOLR(support_auth_oem), /* 0 */
2507 F_BOOLR(support_auth_straight),
2508 F_BOOLR(support_auth_md5),
2509 F_BOOLR(support_auth_md2),
2510 F_BOOLR(support_auth_none),
2511 F_INT(ip_addr_source), /* 5 */
2512 F_INTV(ipv4_ttl),
2513 F_INTV(ipv4_flags),
2514 F_INTV(ipv4_precedence),
2515 F_INTV(ipv4_tos),
2516 F_BOOLIV(enable_auth_oem, ret_user_cnt), /* 10 */
2517 F_BOOLIV(enable_auth_straight, ret_user_cnt),
2518 F_BOOLIV(enable_auth_md5, ret_user_cnt),
2519 F_BOOLIV(enable_auth_md2, ret_user_cnt),
2520 F_BOOLIV(enable_auth_none, ret_user_cnt),
2521 F_IP(ip_addr), /* 15 */
2522 F_MAC(mac_addr),
2523 F_IP(subnet_mask),
2524 F_INTV(port_rmcp_primary),
2525 F_INTV(port_rmcp_secondary),
2526 F_BOOLV(bmc_generated_arps), /* 20 */
2527 F_BOOLV(bmc_generated_garps),
2528 F_INTV(garp_interval),
2529 F_IP(default_gateway_ip_addr),
2530 F_MAC(default_gateway_mac_addr),
2531 F_IP(backup_gateway_ip_addr), /* 25 */
2532 F_MAC(backup_gateway_mac_addr),
2533 F_DATA(community_string),
2534 F_INTR(num_alert_destinations),
2535 F_BOOLIV(alert_ack, ipmi_lanconfig_get_num_alert_destinations),
2536 F_INTIV(dest_type, ipmi_lanconfig_get_num_alert_destinations), /* 30 */
2537 F_INTIV(alert_retry_interval, ipmi_lanconfig_get_num_alert_destinations),
2538 F_INTIV(max_alert_retries, ipmi_lanconfig_get_num_alert_destinations),
2539 F_INTIV(dest_format, ipmi_lanconfig_get_num_alert_destinations),
2540 F_INTIV(gw_to_use, ipmi_lanconfig_get_num_alert_destinations),
2541 F_IPIV(dest_ip_addr, ipmi_lanconfig_get_num_alert_destinations), /* 35 */
2542 F_MACIV(dest_mac_addr, ipmi_lanconfig_get_num_alert_destinations),
2543 F_INTIV(dest_vlan_tag_type, ipmi_lanconfig_get_num_alert_destinations),
2544 F_INTIV(dest_vlan_tag, ipmi_lanconfig_get_num_alert_destinations),
2545 F_BOOLV(vlan_id_enable),
2546 F_INTV(vlan_id), /* 40 */
2547 F_INTV(vlan_priority),
2548 F_INTR(num_cipher_suites),
2549 F_INTIV(cipher_suite_entry, ipmi_lanconfig_get_num_cipher_suites),
2550 F_INTIV(max_priv_for_cipher_suite, ipmi_lanconfig_get_num_cipher_suites)
2551 };
2552 #define NUM_GDATA_ENTRIES (sizeof(gdata) / sizeof(lanparm_gendata_t))
2553
2554 int
ipmi_lanconfig_enum_val(unsigned int parm,int val,int * nval,const char ** sval)2555 ipmi_lanconfig_enum_val(unsigned int parm, int val, int *nval,
2556 const char **sval)
2557 {
2558 char *rval;
2559 int rnval;
2560 if (parm == 5) { /* ip_addr_source */
2561 if (val < 0) {
2562 if (nval)
2563 *nval = 0;
2564 return EINVAL;
2565 }
2566 switch (val) {
2567 case 0:
2568 rval = "unspecified";
2569 rnval = 1;
2570 break;
2571 case 1:
2572 rval = "manually configured";
2573 rnval = 2;
2574 break;
2575 case 2:
2576 rval = "DHCP";
2577 rnval = 3;
2578 break;
2579 case 3:
2580 rval = "BIOS configured";
2581 rnval = 4;
2582 break;
2583 case 4:
2584 rval = "other protocol";
2585 rnval = -1;
2586 break;
2587 default:
2588 if (*nval)
2589 *nval = -1;
2590 return EINVAL;
2591 }
2592 } else if (parm == 43) { /* cipher_suite_entry */
2593 if (val < 0) {
2594 if (nval)
2595 *nval = 0;
2596 return EINVAL;
2597 }
2598 switch (val) {
2599 case 0: rval = "RAKP-none,none,none"; rnval = 1; break;
2600 case 1: rval = "RAKP-HMAC-SHA1,none,none"; rnval = 2; break;
2601 case 2: rval = "RAKP-HMAC-SHA1,HMAC-SHA1-96,none"; rnval = 3; break;
2602 case 3: rval = "RAKP-HMAC-SHA1,HMAC-SHA1-96,AES-CBC-128"; rnval = 4; break;
2603 case 4: rval = "RAKP-HMAC-SHA1,HMAC-SHA1-96,xRC4-128"; rnval = 5; break;
2604 case 5: rval = "RAKP-HMAC-SHA1,HMAC-SHA1-96,xRC4-40"; rnval = 6; break;
2605 case 6: rval = "RAKP-HMAC-MD5,none,none"; rnval = 7; break;
2606 case 7: rval = "RAKP-HMAC-MD5,HMAC-MD5-128,none"; rnval = 8; break;
2607 case 8: rval = "RAKP-HMAC-MD5,HMAC-MD5-128,AES-CBC-128"; rnval = 9; break;
2608 case 9: rval = "RAKP-HMAC-MD5,HMAC-MD5-128,xRC4-128"; rnval = 10; break;
2609 case 10: rval = "RAKP-HMAC-MD5,HMAC-MD5-128,xRC4-40"; rnval = 11; break;
2610 case 11: rval = "RAKP-HMAC-MD5,MD5-128,none"; rnval = 12; break;
2611 case 12: rval = "RAKP-HMAC-MD5,MD5-128,AES-CBC-128"; rnval = 13; break;
2612 case 13: rval = "RAKP-HMAC-MD5,MD5-128,xRC4-128"; rnval = 14; break;
2613 case 14: rval = "RAKP-HMAC-MD5,MD5-128,xRC4-40"; rnval = -1; break;
2614 default:
2615 if (*nval)
2616 *nval = -1;
2617 return EINVAL;
2618 }
2619 } else if (parm == 44) { /* max_priv_for_cipher_suite */
2620 if (val < 0) {
2621 if (nval)
2622 *nval = 0;
2623 return EINVAL;
2624 }
2625 switch (val) {
2626 case 0: rval = "disabled"; rnval = 1; break;
2627 case 1: rval = "callback"; rnval = 2; break;
2628 case 2: rval = "user"; rnval = 3; break;
2629 case 3: rval = "admin"; rnval = 4; break;
2630 case 4: rval = "oem"; rnval = -1; break;
2631 default:
2632 if (*nval)
2633 *nval = -1;
2634 return EINVAL;
2635 }
2636 } else {
2637 return ENOSYS;
2638 }
2639
2640 if (sval)
2641 *sval = rval;
2642 if (nval)
2643 *nval = rnval;
2644 return 0;
2645 }
2646
2647 int
ipmi_lanconfig_enum_idx(unsigned int parm,int idx,const char ** sval)2648 ipmi_lanconfig_enum_idx(unsigned int parm, int idx, const char **sval)
2649 {
2650 char *rval;
2651
2652 if ((parm < 10) || (parm > 14))
2653 return ENOSYS;
2654
2655 switch (idx) {
2656 case 0: rval = "callback"; break;
2657 case 1: rval = "user"; break;
2658 case 2: rval = "operator"; break;
2659 case 3: rval = "admin"; break;
2660 case 4: rval = "oem"; break;
2661 default: return EINVAL;
2662 }
2663
2664 if (sval)
2665 *sval = rval;
2666
2667 return 0;
2668 }
2669
2670 int
ipmi_lanconfig_get_val(ipmi_lan_config_t * lanc,unsigned int parm,const char ** name,int * index,enum ipmi_lanconf_val_type_e * valtype,unsigned int * ival,unsigned char ** dval,unsigned int * dval_len)2671 ipmi_lanconfig_get_val(ipmi_lan_config_t *lanc,
2672 unsigned int parm,
2673 const char **name,
2674 int *index,
2675 enum ipmi_lanconf_val_type_e *valtype,
2676 unsigned int *ival,
2677 unsigned char **dval,
2678 unsigned int *dval_len)
2679 {
2680 unsigned int curr = *index;
2681 unsigned int count;
2682 int rv = 0;
2683 unsigned char *data;
2684 unsigned int data_len;
2685
2686 if (parm >= NUM_GDATA_ENTRIES)
2687 return EINVAL;
2688 if (valtype)
2689 *valtype = gdata[parm].datatype;
2690 if (name)
2691 *name = gdata[parm].fname;
2692
2693 if (gdata[parm].iv_cnt) {
2694 count = gdata[parm].iv_cnt(lanc);
2695 if (curr >= count) {
2696 *index = -1;
2697 return E2BIG;
2698 }
2699
2700 if (curr+1 == count)
2701 *index = -1;
2702 else
2703 *index = curr+1;
2704 }
2705
2706 switch (gdata[parm].datatype) {
2707 case IPMI_LANCONFIG_INT:
2708 case IPMI_LANCONFIG_BOOL:
2709 if (!ival)
2710 break;
2711 if (gdata[parm].u.ival.gval)
2712 *ival = gdata[parm].u.ival.gval(lanc);
2713 else if (gdata[parm].u.ival.gval_v)
2714 rv = gdata[parm].u.ival.gval_v(lanc, ival);
2715 else if (gdata[parm].u.ival.gval_iv)
2716 rv = gdata[parm].u.ival.gval_iv(lanc, curr, ival);
2717 else
2718 rv = ENOSYS;
2719 break;
2720
2721 case IPMI_LANCONFIG_DATA:
2722 case IPMI_LANCONFIG_IP:
2723 case IPMI_LANCONFIG_MAC:
2724 data_len = 0;
2725 if (gdata[parm].u.dval.gval_v)
2726 rv = gdata[parm].u.dval.gval_v(lanc, NULL, &data_len);
2727 else if (gdata[parm].u.dval.gval_iv)
2728 rv = gdata[parm].u.dval.gval_iv(lanc, curr, NULL, &data_len);
2729 else
2730 rv = ENOSYS;
2731 if (rv && (rv != EBADF))
2732 break;
2733 if (data_len == 0)
2734 data = ipmi_mem_alloc(1);
2735 else
2736 data = ipmi_mem_alloc(data_len);
2737 if (gdata[parm].u.dval.gval_v)
2738 rv = gdata[parm].u.dval.gval_v(lanc, data, &data_len);
2739 else if (gdata[parm].u.dval.gval_iv)
2740 rv = gdata[parm].u.dval.gval_iv(lanc, curr, data, &data_len);
2741 if (rv) {
2742 ipmi_mem_free(data);
2743 break;
2744 }
2745 if (dval)
2746 *dval = data;
2747 if (dval_len)
2748 *dval_len = data_len;
2749 break;
2750 }
2751
2752 return rv;
2753 }
2754
2755 int
ipmi_lanconfig_set_val(ipmi_lan_config_t * lanc,unsigned int parm,int index,unsigned int ival,unsigned char * dval,unsigned int dval_len)2756 ipmi_lanconfig_set_val(ipmi_lan_config_t *lanc,
2757 unsigned int parm,
2758 int index,
2759 unsigned int ival,
2760 unsigned char *dval,
2761 unsigned int dval_len)
2762 {
2763 unsigned int count;
2764 int rv = 0;
2765
2766 if (parm >= NUM_GDATA_ENTRIES)
2767 return EINVAL;
2768
2769 if (gdata[parm].iv_cnt) {
2770 count = gdata[parm].iv_cnt(lanc);
2771 if (index >= (int) count)
2772 return E2BIG;
2773 }
2774
2775 switch (gdata[parm].datatype) {
2776 case IPMI_LANCONFIG_INT:
2777 case IPMI_LANCONFIG_BOOL:
2778 if (gdata[parm].u.ival.sval)
2779 rv = gdata[parm].u.ival.sval(lanc, ival);
2780 else if (gdata[parm].u.ival.sval_v)
2781 rv = gdata[parm].u.ival.sval_v(lanc, ival);
2782 else if (gdata[parm].u.ival.sval_iv)
2783 rv = gdata[parm].u.ival.sval_iv(lanc, index, ival);
2784 else
2785 rv = ENOSYS;
2786 break;
2787
2788 case IPMI_LANCONFIG_DATA:
2789 case IPMI_LANCONFIG_IP:
2790 case IPMI_LANCONFIG_MAC:
2791 if (gdata[parm].u.dval.sval_v)
2792 rv = gdata[parm].u.dval.sval_v(lanc, dval, dval_len);
2793 else if (gdata[parm].u.dval.sval_iv)
2794 rv = gdata[parm].u.dval.sval_iv(lanc, index, dval, dval_len);
2795 else
2796 rv = ENOSYS;
2797 break;
2798 }
2799
2800 return rv;
2801 }
2802
2803
2804 void
ipmi_lanconfig_data_free(void * data)2805 ipmi_lanconfig_data_free(void *data)
2806 {
2807 ipmi_mem_free(data);
2808 }
2809
2810 unsigned int
ipmi_lanconfig_str_to_parm(char * name)2811 ipmi_lanconfig_str_to_parm(char *name)
2812 {
2813 unsigned int i;
2814 for (i=0; i<NUM_GDATA_ENTRIES; i++) {
2815 if (strcmp(name, gdata[i].fname) == 0)
2816 return i;
2817 }
2818 return -1;
2819 }
2820
2821 const char *
ipmi_lanconfig_parm_to_str(unsigned int parm)2822 ipmi_lanconfig_parm_to_str(unsigned int parm)
2823 {
2824 if (parm >= NUM_GDATA_ENTRIES)
2825 return NULL;
2826 return gdata[parm].fname;
2827 }
2828
2829 int
ipmi_lanconfig_parm_to_type(unsigned int parm,enum ipmi_lanconf_val_type_e * valtype)2830 ipmi_lanconfig_parm_to_type(unsigned int parm,
2831 enum ipmi_lanconf_val_type_e *valtype)
2832 {
2833 if (parm >= NUM_GDATA_ENTRIES)
2834 return EINVAL;
2835 *valtype = gdata[parm].datatype;
2836 return 0;
2837 }
2838