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