1 /*
2  * Copyright (c) 2016 Pentair Technical Products. All right reserved
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Pentair Technical Products or the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23  * PENTAIR TECHNICAL SOLUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <ipmitool/helper.h>
34 #include <ipmitool/ipmi_cc.h>
35 #include <ipmitool/ipmi_cfgp.h>
36 #include <ipmitool/ipmi_lanp.h>
37 #include <ipmitool/ipmi_lanp6.h>
38 #include <ipmitool/log.h>
39 
40 #include <errno.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <arpa/inet.h>
44 
45 /*
46  * LAN6 command values.
47  */
48 enum {
49 	LANP_CMD_SAVE,
50 	LANP_CMD_SET,
51 	LANP_CMD_PRINT,
52 	LANP_CMD_LOCK,
53 	LANP_CMD_COMMIT,
54 	LANP_CMD_DISCARD,
55 	LANP_CMD_HELP,
56 	LANP_CMD_ANY = 0xFF
57 };
58 
59 /*
60  * Generic LAN configuration parameters.
61  */
62 const struct ipmi_lanp generic_lanp6[] = {
63 	{ 0,	"Set In Progress", 1 },
64 	{ 50,	"IPv6/IPv4 Support", 1 },
65 	{ 51,	"IPv6/IPv4 Addressing Enables", 1 },
66 	{ 52,	"IPv6 Header Traffic Class", 1 },
67 	{ 53,	"IPv6 Header Static Hop Limit", 1 },
68 	{ 54,	"IPv6 Header Flow Label", 3 },
69 	{ 55,	"IPv6 Status", 3 },
70 	{ 56,	"IPv6 Static Address", 20 },
71 	{ 57,	"IPv6 DHCPv6 Static DUID Storage Length", 1 },
72 	{ 58,	"IPv6 DHCPv6 Static DUID", 18 },
73 	{ 59,	"IPv6 Dynamic Address", 20 },
74 	{ 60,	"IPv6 DHCPv6 Dynamic DUID Storage Length", 1 },
75 	{ 61,	"IPv6 DHCPv6 Dynamic DUID", 18 },
76 	{ 62,	"IPv6 DHCPv6 Timing Configuration Support", 1 },
77 	{ 63,	"IPv6 DHCPv6 Timing Configuration", 18 },
78 	{ 64,	"IPv6 Router Address Configuration Control", 1 },
79 	{ 65,	"IPv6 Static Router 1 IP Address", 16 },
80 	{ 66,	"IPv6 Static Router 1 MAC Address", 6 },
81 	{ 67,	"IPv6 Static Router 1 Prefix Length", 1 },
82 	{ 68,	"IPv6 Static Router 1 Prefix Value", 16 },
83 	{ 69,	"IPv6 Static Router 2 IP Address", 16 },
84 	{ 70,	"IPv6 Static Router 2 MAC Address", 6 },
85 	{ 71,	"IPv6 Static Router 2 Prefix Length", 1 },
86 	{ 72,	"IPv6 Static Router 2 Prefix Value", 16 },
87 	{ 73,	"IPv6 Number of Dynamic Router Info Sets", 1 },
88 	{ 74,	"IPv6 Dynamic Router Info IP Address", 17 },
89 	{ 75,	"IPv6 Dynamic Router Info MAC Address", 7 },
90 	{ 76,	"IPv6 Dynamic Router Info Prefix Length", 2 },
91 	{ 77,	"IPv6 Dynamic Router Info Prefix Value", 17 },
92 	{ 78,	"IPv6 Dynamic Router Received Hop Limit", 1 },
93 	{ 79,	"IPv6 ND/SLAAC Timing Configuration Support", 1 },
94 	{ 80,	"IPv6 ND/SLAAC Timing Configuration", 18 },
95 	{ 0,	NULL, 0 }
96 };
97 
98 /*
99  * Set/Get LAN Configuration Parameters
100  * command-specific completion codes.
101  */
102 const struct valstr lanp_cc_vals[] = {
103 	{ 0x80, "Parameter not supported" },
104 	{ 0x81, "Set already in progress" },
105 	{ 0x82, "Parameter is read-only" },
106 	{ 0x83, "Write-only parameter" },
107 	{ 0x00, NULL }
108 };
109 
110 /*
111  * IPv6/IPv4 Addressing Enables.
112  */
113 const struct valstr ip6_enable_vals[] = {
114 	{ 0, "ipv4" },
115 	{ 1, "ipv6" },
116 	{ 2, "both" },
117 	{ 0xFF, NULL }
118 };
119 
120 /*
121  * Enable/Disable a static address.
122  */
123 const struct valstr ip6_addr_enable_vals[] = {
124 	{ 0x00, "disable" },
125 	{ 0x80, "enable" },
126 	{ 0xFF, NULL }
127 };
128 
129 /*
130  * IPv6 address source values.
131  */
132 const struct valstr ip6_addr_sources[] = {
133 	{ 0, "static" },
134 	{ 1, "SLAAC" },
135 	{ 2, "DHCPv6" },
136 	{ 0, NULL }
137 };
138 
139 /*
140  * IPv6 address status values.
141  */
142 const struct valstr ip6_addr_statuses[] = {
143 	{ 0, "active" },
144 	{ 1, "disabled" },
145 	{ 2, "pending" },
146 	{ 3, "failed" },
147 	{ 4, "deprecated" },
148 	{ 5, "invalid" },
149 	{ 0xFF, NULL }
150 };
151 
152 /*
153  * DHCPv6 DUID type values.
154  */
155 const struct valstr ip6_duid_types[] = {
156 	{ 0, "unknown" },
157 	{ 1, "DUID-LLT" },
158 	{ 2, "DUID-EN" },
159 	{ 3, "DUID-LL" },
160 	{ 0xFF, NULL }
161 };
162 
163 /*
164  * Timing Configuration support values.
165  */
166 const struct valstr ip6_cfg_sup_vals[] = {
167 	{ 0, "not supported" },
168 	{ 1, "global" },
169 	{ 2, "per interface" },
170 	{ 0xFF, NULL }
171 };
172 
173 /*
174  * Router Address Configuration Control values.
175  */
176 const struct valstr ip6_rtr_configs[] = {
177 	{ 1, "static" },
178 	{ 2, "dynamic" },
179 	{ 3, "both" },
180 	{ 0xFF, NULL }
181 };
182 
183 
184 const struct valstr ip6_command_vals[] = {
185 	{ LANP_CMD_SET,		"set" },
186 	{ LANP_CMD_SAVE,	"save" },
187 	{ LANP_CMD_PRINT,	"print" },
188 	{ LANP_CMD_LOCK,	"lock" },
189 	{ LANP_CMD_COMMIT,	"commit" },
190 	{ LANP_CMD_DISCARD,	"discard" },
191 	{ LANP_CMD_HELP,	"help" },
192 	{ LANP_CMD_ANY,		NULL }
193 };
194 
195 static const struct ipmi_cfgp lan_cfgp[] = {
196 	{ .name = "support", .format = NULL, .size = 1,
197 		.access = CFGP_RDONLY,
198 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
199 		.specific = IPMI_LANP_IP6_SUPPORT
200 	},
201 	{ .name = "enables", .format = "{ipv4|ipv6|both}", .size = 1,
202 		.access = CFGP_RDWR,
203 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
204 		.specific = IPMI_LANP_IP6_ENABLES
205 	},
206 	{ .name = "traffic_class", .format = "<value>", .size = 1,
207 		.access = CFGP_RDWR,
208 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
209 		.specific = IPMI_LANP_IP6_TRAFFIC_CLASS
210 	},
211 	{ .name = "static_hops", .format = "<value>", .size = 1,
212 		.access = CFGP_RDWR,
213 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
214 		.specific = IPMI_LANP_IP6_STATIC_HOPS
215 	},
216 	{ .name = "flow_label", .format = "<value>", .size = 3,
217 		.access = CFGP_RDWR,
218 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
219 		.specific = IPMI_LANP_IP6_FLOW_LABEL
220 	},
221 	{ .name = "status", .format = NULL, .size = 3,
222 		.access = CFGP_RDONLY,
223 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
224 		.specific = IPMI_LANP_IP6_STATUS
225 	},
226 	{ .name = "static_addr",
227 		.format = "{enable|disable} <addr> <pfx_len>", .size = 20,
228 		.access = CFGP_RDWR,
229 		.is_set = 1, .first_set = 0, .has_blocks = 0, .first_block = 0,
230 		.specific = IPMI_LANP_IP6_STATIC_ADDR
231 	},
232 	{ .name = "static_duid_stg", .format = NULL, .size = 1,
233 		.access = CFGP_RDONLY,
234 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
235 		.specific = IPMI_LANP_IP6_STATIC_DUID_STG
236 	},
237 	{ .name = "static_duid", .format = "<data>", .size = 18,
238 		.access = CFGP_RDWR,
239 		.is_set = 1, .first_set = 0, .has_blocks = 1, .first_block = 0,
240 		.specific = IPMI_LANP_IP6_STATIC_DUID
241 	},
242 	{ .name = "dynamic_addr", .format = NULL, .size = 20,
243 		.access = CFGP_RDONLY,
244 		.is_set = 1, .first_set = 0, .has_blocks = 0, .first_block = 0,
245 		.specific = IPMI_LANP_IP6_DYNAMIC_ADDR
246 	},
247 	{ .name = "dynamic_duid_stg", .format = NULL, .size = 1,
248 		.access = CFGP_RDONLY,
249 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
250 		.specific = IPMI_LANP_IP6_DYNAMIC_DUID_STG
251 	},
252 	{ .name = "dynamic_duid", .format = "<data>", .size = 18,
253 		.access = CFGP_RDWR,
254 		.is_set = 1, .first_set = 0, .has_blocks = 1, .first_block = 0,
255 		.specific = IPMI_LANP_IP6_DYNAMIC_DUID
256 	},
257 	{ .name = "dhcp6_cfg_sup", .format = NULL, .size = 1,
258 		.access = CFGP_RDONLY,
259 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
260 		.specific = IPMI_LANP_IP6_DHCP6_CFG_SUP
261 	},
262 	{ .name = "dhcp6_cfg", .format = "<data> <data>", .size = 36,
263 		.access = CFGP_RDWR,
264 		.is_set = 1, .first_set = 0, .has_blocks = 0, .first_block = 0,
265 		.specific = IPMI_LANP_IP6_DHCP6_CFG
266 	},
267 	{ .name = "rtr_cfg", .format = "{static|dynamic|both}", .size = 1,
268 		.access = CFGP_RDWR,
269 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
270 		.specific = IPMI_LANP_IP6_ROUTER_CFG
271 	},
272 	{ .name = "static_rtr",
273 		.format = "<addr> <macaddr> <prefix> <prefix_len>", .size = 43,
274 		.access = CFGP_RDWR,
275 		.is_set = 1, .first_set = 1, .has_blocks = 0, .first_block = 0,
276 		.specific = IPMI_LANP_IP6_STATIC_RTR1_ADDR
277 	},
278 	{ .name = "num_dynamic_rtrs", .format = NULL, .size = 1,
279 		.access = CFGP_RDONLY,
280 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
281 		.specific = IPMI_LANP_IP6_NUM_DYNAMIC_RTRS
282 	},
283 	{ .name = "dynamic_rtr", .format = NULL, .size = 43,
284 		.access = CFGP_RDONLY,
285 		.is_set = 1, .first_set = 0, .has_blocks = 0, .first_block = 0,
286 		.specific = IPMI_LANP_IP6_DYNAMIC_RTR_ADDR
287 	},
288 	{ .name = "dynamic_hops", .format = NULL, .size = 1,
289 		.access = CFGP_RDONLY,
290 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
291 		.specific = IPMI_LANP_IP6_DYNAMIC_HOPS
292 	},
293 	{ .name = "ndslaac_cfg_sup", .format = NULL, .size = 1,
294 		.access = CFGP_RDONLY,
295 		.is_set = 0, .first_set = 0, .has_blocks = 0, .first_block = 0,
296 		.specific = IPMI_LANP_IP6_NDSLAAC_CFG_SUP
297 	},
298 	{ .name = "ndslaac_cfg", .format = "<data>", .size = 18,
299 		.access = CFGP_RDWR,
300 		.is_set = 1, .first_set = 0, .has_blocks = 0, .first_block = 0,
301 		.specific = IPMI_LANP_IP6_NDSLAAC_CFG
302 	}
303 };
304 
305 /*
306  * Lookup LAN parameter descriptor by parameter selector.
307  */
308 const struct ipmi_lanp *
lookup_lanp(int param)309 lookup_lanp(int param)
310 {
311 	const struct ipmi_lanp *p = generic_lanp6;
312 
313 	while (p->name) {
314 		if (p->selector == param) {
315 			return p;
316 		}
317 
318 		p++;
319 	}
320 
321 	return NULL;
322 }
323 
324 /*
325  * Print request error.
326  */
327 static int
ipmi_lanp_err(const struct ipmi_rs * rsp,const struct ipmi_lanp * p,const char * action,int quiet)328 ipmi_lanp_err(const struct ipmi_rs *rsp, const struct ipmi_lanp *p,
329 		const char *action, int quiet)
330 {
331 	const char *reason;
332 	char cc_msg[10];
333 	int log_level = LOG_ERR;
334 	int err;
335 
336 	if (rsp == NULL) {
337 		reason = "No response";
338 		err = -1;
339 	} else {
340 		err = rsp->ccode;
341 		if (quiet == 1
342 			&& (rsp->ccode == 0x80
343 			|| rsp->ccode == IPMI_CC_PARAM_OUT_OF_RANGE
344 			|| rsp->ccode == IPMI_CC_INV_DATA_FIELD_IN_REQ)) {
345 			/* be quiet */
346 			return err;
347 		}
348 
349 		if (rsp->ccode >= 0xC0) {
350 			/* browse for generic completion codes */
351 			reason = val2str(rsp->ccode, completion_code_vals);
352 		} else {
353 			/* browse for command-specific completion codes first */
354 			reason = val2str(rsp->ccode, lanp_cc_vals);
355 		}
356 
357 		if (reason == NULL) {
358 			/* print completion code value */
359 			snprintf(cc_msg, sizeof(cc_msg), "CC=%02x", rsp->ccode);
360 			reason = cc_msg;
361 		}
362 
363 		if (rsp->ccode == IPMI_CC_OK) {
364 			log_level = LOG_DEBUG;
365 		}
366 	}
367 
368 	lprintf(log_level, "Failed to %s %s: %s", action, p->name, reason);
369 	return err;
370 }
371 
372 /*
373  * Get dynamic OEM LAN configuration parameter from BMC.
374  * Dynamic in this context is when the base for OEM LAN parameters
375  * is not known apriori.
376  */
377 int
ipmi_get_dynamic_oem_lanp(void * priv,const struct ipmi_lanp * param,int oem_base,int set_selector,int block_selector,void * data,int quiet)378 ipmi_get_dynamic_oem_lanp(void *priv, const struct ipmi_lanp *param,
379 		int oem_base, int set_selector, int block_selector,
380 		void *data, int quiet)
381 {
382 	struct ipmi_lanp_priv *lp = priv;
383 	struct ipmi_rs *rsp;
384 	struct ipmi_rq req;
385 	uint8_t req_data[4];
386 	int length;
387 
388 	if (!priv || !param || !data) {
389 		return -1;
390 	}
391 	req_data[0] = lp->channel;
392 	req_data[1] = param->selector + oem_base;
393 	req_data[2] = set_selector;
394 	req_data[3] = block_selector;
395 
396 	memset(&req, 0, sizeof(req));
397 	req.msg.netfn    = IPMI_NETFN_TRANSPORT;
398 	req.msg.cmd      = 2;
399 	req.msg.data     = req_data;
400 	req.msg.data_len = 4;
401 
402 	lprintf(LOG_INFO, "Getting parameter '%s' set %d block %d",
403 		param->name, set_selector, block_selector);
404 
405 	rsp = lp->intf->sendrecv(lp->intf, &req);
406 	if (rsp == NULL || rsp->ccode) {
407 		return ipmi_lanp_err(rsp, param, "get", quiet);
408 	}
409 
410 	memset(data, 0, param->size);
411 
412 	if (rsp->data_len - 1 < param->size) {
413 		length = rsp->data_len - 1;
414 	} else {
415 		length = param->size;
416 	}
417 
418 	if (length) {
419 		memcpy(data, rsp->data + 1, length);
420 	}
421 
422 	return 0;
423 }
424 
425 /*
426  * Get generic LAN configuration parameter.
427  */
428 int
ipmi_get_lanp(void * priv,int param_selector,int set_selector,int block_selector,void * data,int quiet)429 ipmi_get_lanp(void *priv, int param_selector, int set_selector,
430 		int block_selector, void *data, int quiet)
431 {
432 	return ipmi_get_dynamic_oem_lanp(priv, lookup_lanp(param_selector), 0,
433 			set_selector, block_selector, data, quiet);
434 }
435 
436 /*
437  * Set dynamic OEM LAN configuration parameter to BMC.
438  * Dynamic in this context is when the base for OEM LAN parameters
439  * is not known apriori.
440  */
441 int
ipmi_set_dynamic_oem_lanp(void * priv,const struct ipmi_lanp * param,int base,const void * data)442 ipmi_set_dynamic_oem_lanp(void *priv, const struct ipmi_lanp *param,
443 		int base, const void *data)
444 {
445 	struct ipmi_lanp_priv *lp = priv;
446 	struct ipmi_rs *rsp;
447 	struct ipmi_rq req;
448 	uint8_t req_data[32];
449 
450 	if (!priv || !param || !data) {
451 		return -1;
452 	}
453 	/* fill the first two bytes */
454 	req_data[0] = lp->channel;
455 	req_data[1] = param->selector + base;
456 
457 	/* fill the rest data */
458 	memcpy(&req_data[2], data, param->size);
459 
460 	/* fill request */
461 	memset(&req, 0, sizeof(req));
462 	req.msg.netfn    = IPMI_NETFN_TRANSPORT;
463 	req.msg.cmd      = 1;
464 	req.msg.data     = req_data;
465 	req.msg.data_len = param->size + 2;
466 
467 	lprintf(LOG_INFO, "Setting parameter '%s'", param->name);
468 
469 	rsp = lp->intf->sendrecv(lp->intf, &req);
470 	if (rsp == NULL || rsp->ccode) {
471 		return ipmi_lanp_err(rsp, param, "set", 0);
472 	}
473 
474 	return 0;
475 }
476 
477 /*
478  * Set generic LAN configuration parameter.
479  */
480 int
ipmi_set_lanp(void * priv,int param_selector,const void * data)481 ipmi_set_lanp(void *priv, int param_selector, const void *data)
482 {
483 	return ipmi_set_dynamic_oem_lanp(priv, lookup_lanp(param_selector),
484 		0, data);
485 }
486 
487 static int
lanp_parse_cfgp(const struct ipmi_cfgp * p,int set,int block,int argc,const char * argv[],unsigned char * data)488 lanp_parse_cfgp(const struct ipmi_cfgp *p, int set, int block,
489 		int argc, const char *argv[], unsigned char *data)
490 {
491 	unsigned int v;
492 
493 	if (argc == 0) {
494 		return -1;
495 	}
496 
497 	switch(p->specific) {
498 	case IPMI_LANP_IP6_ENABLES:
499 		data[0] = str2val(argv[0], ip6_enable_vals);
500 		if (data[0] == 0xFF) {
501 			lprintf(LOG_ERR, "invalid value");
502 			return -1;
503 		}
504 		break;
505 
506 	case IPMI_LANP_IP6_FLOW_LABEL:
507 		if (str2uint(argv[0], &v)) {
508 			lprintf(LOG_ERR, "invalid value");
509 			return -1;
510 		}
511 
512 		data[0] = (v >> 16) & 0x0F;
513 		data[1] = (v >> 8) & 0xFF;
514 		data[2] = v & 0xFF;
515 		break;
516 
517 	case IPMI_LANP_IP6_STATUS:
518 		if (argc < 3) {
519 			return -1;
520 		}
521 
522 		if (str2uchar(argv[0], &data[0])
523 				|| str2uchar(argv[1], &data[1])
524 				|| str2uchar(argv[2], &data[2])) {
525 			lprintf(LOG_ERR, "invalid value");
526 			return -1;
527 		}
528 		break;
529 
530 	case IPMI_LANP_IP6_STATIC_ADDR:
531 	case IPMI_LANP_IP6_DYNAMIC_ADDR:
532 		if (argc < 3) {
533 			return -1;
534 		}
535 
536 		data[0] = set;
537 		if (p->specific == IPMI_LANP_IP6_STATIC_ADDR) {
538 			data[1] = str2val(argv[0], ip6_addr_enable_vals);
539 		} else {
540 			data[1] = str2val(argv[0], ip6_addr_sources);
541 		}
542 		if (data[1] == 0xFF) {
543 			lprintf(LOG_ERR, "invalid value");
544 			return -1;
545 		}
546 
547 		if (inet_pton(AF_INET6, argv[1], &data[2]) != 1) {
548 			lprintf(LOG_ERR, "invalid value");
549 			return -1;
550 		}
551 
552 		if (str2uchar(argv[2], &data[18])) {
553 			lprintf(LOG_ERR, "invalid value");
554 			return -1;
555 		}
556 
557 		if (argc >= 4) {
558 			data[19] = str2val(argv[3], ip6_addr_statuses);
559 		}
560 		break;
561 
562 	case IPMI_LANP_IP6_STATIC_DUID:
563 	case IPMI_LANP_IP6_DYNAMIC_DUID:
564 	case IPMI_LANP_IP6_NDSLAAC_CFG:
565 		data[0] = set;
566 		data[1] = block;
567 		if (ipmi_parse_hex(argv[0], &data[2], 16) < 0) {
568 			lprintf(LOG_ERR, "invalid value");
569 			return -1;
570 		}
571 		break;
572 
573 	case IPMI_LANP_IP6_DHCP6_CFG:
574 		data[0] = set;
575 		data[1] = 0;
576 		data[18] = set;
577 		data[19] = 1;
578 
579 		if (ipmi_parse_hex(argv[0], &data[2], 16) < 0
580 			|| (argc > 1 &&
581 			    ipmi_parse_hex(argv[1], &data[20], 6) < 0)) {
582 			lprintf(LOG_ERR, "invalid value");
583 			return -1;
584 		}
585 		break;
586 
587 	case IPMI_LANP_IP6_ROUTER_CFG:
588 		data[0] = str2val(argv[0], ip6_rtr_configs);
589 		if (data[0] == 0xFF) {
590 			lprintf(LOG_ERR, "invalid value");
591 			return -1;
592 		}
593 		break;
594 
595 	case IPMI_LANP_IP6_STATIC_RTR1_ADDR:
596 		if (set > 2) {
597 			lprintf(LOG_ERR, "invalid value");
598 			return -1;
599 		}
600 
601 	case IPMI_LANP_IP6_DYNAMIC_RTR_ADDR:
602 		if (argc < 4) {
603 			return -1;
604 		}
605 
606 		/*
607 		 * Data is stored in the following way:
608 		 *  0: <set> <addr1>...<addr16>
609 		 * 17: <set> <mac1>...<mac6>
610 		 * 24: <set> <pfxlen>
611 		 * 26: <set> <pfx1>...<pfx16>
612 		 */
613 		data[0] = data[17] = data[24] = data[26] = set;
614 
615 		if (inet_pton(AF_INET6, argv[0], &data[1]) != 1
616 				|| str2mac(argv[1], &data[18])
617 				|| inet_pton(AF_INET6, argv[2], &data[27]) != 1
618 				|| str2uchar(argv[3], &data[25])) {
619 			lprintf(LOG_ERR, "invalid value");
620 			return -1;
621 		}
622 		break;
623 
624 	default:
625 		if (str2uchar(argv[0], &data[0])) {
626 			lprintf(LOG_ERR, "invalid value");
627 			return -1;
628 		}
629 	}
630 
631 	return 0;
632 }
633 
634 static int
lanp_set_cfgp(void * priv,const struct ipmi_cfgp * p,const unsigned char * data)635 lanp_set_cfgp(void *priv, const struct ipmi_cfgp *p, const unsigned char *data)
636 {
637 	int ret;
638 	int param = p->specific;
639 	int off = 0;
640 
641 	switch(param) {
642 	case IPMI_LANP_IP6_DHCP6_CFG:
643 		ret = ipmi_set_lanp(priv, param, &data[0]);
644 		if (ret == 0) {
645 			ret = ipmi_set_lanp(priv, param, &data[18]);
646 		}
647 		break;
648 
649 	case IPMI_LANP_IP6_STATIC_RTR1_ADDR:
650 		if (data[0] == 2) {
651 			param = IPMI_LANP_IP6_STATIC_RTR2_ADDR;
652 		}
653 		off = 1;
654 
655 	case IPMI_LANP_IP6_DYNAMIC_RTR_ADDR:
656 		ret = ipmi_set_lanp(priv, param, &data[0 + off]);
657 		if (ret == 0) {
658 			ret = ipmi_set_lanp(priv, param + 1, &data[17 + off]);
659 		}
660 		if (ret == 0) {
661 			ret = ipmi_set_lanp(priv, param + 2, &data[24 + off]);
662 		}
663 		if (ret == 0) {
664 			ret = ipmi_set_lanp(priv, param + 3, &data[26 + off]);
665 		}
666 		break;
667 
668 
669 	default:
670 		ret = ipmi_set_lanp(priv, param, data);
671 	}
672 
673 	return ret;
674 }
675 
676 static int
lanp_get_cfgp(void * priv,const struct ipmi_cfgp * p,int set,int block,unsigned char * data,int quiet)677 lanp_get_cfgp(void *priv, const struct ipmi_cfgp *p,
678 		int set, int block,  unsigned char *data, int quiet)
679 {
680 	int ret;
681 	int param = p->specific;
682 	int off = 0;
683 
684 	switch(param) {
685 	case IPMI_LANP_IP6_DHCP6_CFG:
686 		ret = ipmi_get_lanp(priv, param, set, 0, &data[0], quiet);
687 		if (ret == 0) {
688 			ret = ipmi_get_lanp(priv, param, set,
689 				1, &data[18], quiet);
690 		}
691 		break;
692 
693 	case IPMI_LANP_IP6_STATIC_RTR1_ADDR:
694 		if (set > 2) {
695 			return -1;
696 		}
697 
698 		if (set == 2) {
699 			param = IPMI_LANP_IP6_STATIC_RTR2_ADDR;
700 		}
701 		set = 0;
702 		off = 1;
703 		data[0] = data[17] = data[24] = data[26] = set;
704 
705 	case IPMI_LANP_IP6_DYNAMIC_RTR_ADDR:
706 		ret = ipmi_get_lanp(priv, param, set, block,
707 			&data[0 + off], quiet);
708 		if (ret == 0) {
709 			ret = ipmi_get_lanp(priv, param + 1, set, block,
710 				&data[17 + off], 0);
711 		}
712 		if (ret == 0) {
713 			ret = ipmi_get_lanp(priv, param + 2, set, block,
714 				&data[24 + off], 0);
715 		}
716 		if (ret == 0) {
717 			ret = ipmi_get_lanp(priv, param + 3, set, block,
718 				&data[26 + off], 0);
719 		}
720 		break;
721 
722 	default:
723 		ret = ipmi_get_lanp(priv, param, set, block, data, quiet);
724 	}
725 
726 	return ret;
727 }
728 
729 static int
lanp_save_cfgp(const struct ipmi_cfgp * p,const unsigned char * data,FILE * file)730 lanp_save_cfgp(const struct ipmi_cfgp *p, const unsigned char *data, FILE *file)
731 {
732 	char addr[INET6_ADDRSTRLEN];
733 	char pfx[INET6_ADDRSTRLEN];
734 	const char *src;
735 
736 	switch(p->specific) {
737 	case IPMI_LANP_IP6_ENABLES:
738 		fputs(val2str(data[0], ip6_enable_vals), file);
739 		break;
740 
741 	case IPMI_LANP_IP6_FLOW_LABEL:
742 		fprintf(file, "0x%xd", (data[0] << 16 ) | (data[1] << 8) | data[2]);
743 		break;
744 
745 	case IPMI_LANP_IP6_STATUS:
746 		fprintf(file, "%d %d %d", data[0], data[1], data[2]);
747 		break;
748 
749 	case IPMI_LANP_IP6_STATIC_ADDR:
750 	case IPMI_LANP_IP6_DYNAMIC_ADDR:
751 		if (p->specific == IPMI_LANP_IP6_STATIC_ADDR) {
752 			src = val2str(data[1], ip6_addr_enable_vals);
753 		} else {
754 			src = val2str(data[1], ip6_addr_sources);
755 		}
756 
757 		fprintf(file, "%s %s %d %s", src,
758 				inet_ntop(AF_INET6, &data[2], addr, sizeof(addr)),
759 				data[18], val2str(data[19], ip6_addr_statuses));
760 		break;
761 
762 	case IPMI_LANP_IP6_STATIC_DUID:
763 	case IPMI_LANP_IP6_DYNAMIC_DUID:
764 	case IPMI_LANP_IP6_NDSLAAC_CFG:
765 		fprintf(file, "%s", buf2str(&data[2], 16));
766 		break;
767 
768 	case IPMI_LANP_IP6_DHCP6_CFG:
769 		fprintf(file, "%s", buf2str(&data[2], 16));
770 		fprintf(file, " %s", buf2str(&data[20], 6));
771 		break;
772 
773 	case IPMI_LANP_IP6_ROUTER_CFG:
774 		fputs(val2str(data[0], ip6_rtr_configs), file);
775 		break;
776 
777 	case IPMI_LANP_IP6_STATIC_RTR1_ADDR:
778 	case IPMI_LANP_IP6_DYNAMIC_RTR_ADDR:
779 		fprintf(file, "%s %s %s %d",
780 				inet_ntop(AF_INET6, &data[1], addr, sizeof(addr)),
781 				mac2str(&data[18]),
782 				inet_ntop(AF_INET6, &data[27], pfx, sizeof(pfx)), data[25]);
783 		break;
784 
785 	default:
786 		fprintf(file, "%d", data[0]);
787 	}
788 
789 	return 0;
790 }
791 
792 
793 static int
lanp_print_cfgp(const struct ipmi_cfgp * p,int set,int block,const unsigned char * data,FILE * file)794 lanp_print_cfgp(const struct ipmi_cfgp *p,
795 		int set, int block, const unsigned char *data, FILE *file)
796 {
797 	char addr[INET6_ADDRSTRLEN];
798 	char pfx[INET6_ADDRSTRLEN];
799 	const char *pname;
800 	const struct ipmi_lanp *lanp = lookup_lanp(p->specific);
801 
802 	if (!lanp || !p || !file || !data || !lanp->name) {
803 		return -1;
804 	}
805 	pname = lanp->name;
806 
807 	switch(p->specific) {
808 	case IPMI_LANP_IP6_SUPPORT:
809 		fprintf(file, "%s:\n"
810 				"    IPv6 only: %s\n"
811 				"    IPv4 and IPv6: %s\n"
812 				"    IPv6 Destination Addresses for LAN alerting: %s\n",
813 				pname,
814 				data[0] & 1 ? "yes" : "no",
815 				data[0] & 2 ? "yes" : "no",
816 				data[0] & 4 ? "yes" : "no");
817 		break;
818 
819 	case IPMI_LANP_IP6_ENABLES:
820 		fprintf(file, "%s: %s\n",
821 				pname, val2str(data[0], ip6_enable_vals));
822 		break;
823 
824 	case IPMI_LANP_IP6_FLOW_LABEL:
825 		fprintf(file, "%s: %d\n",
826 				pname, (data[0] << 16 ) | (data[1] << 8) | data[2]);
827 		break;
828 
829 	case IPMI_LANP_IP6_STATUS:
830 		fprintf(file, "%s:\n"
831 				"    Static address max:  %d\n"
832 				"    Dynamic address max: %d\n"
833 				"    DHCPv6 support:      %s\n"
834 				"    SLAAC support:       %s\n",
835 				pname,
836 				data[0], data[1],
837 				(data[2] & 1) ? "yes" : "no",
838 				(data[2] & 2) ? "yes" : "no");
839 		break;
840 
841 	case IPMI_LANP_IP6_STATIC_ADDR:
842 		fprintf(file, "%s %d:\n"
843 				"    Enabled:        %s\n"
844 				"    Address:        %s/%d\n"
845 				"    Status:         %s\n",
846 				pname, set,
847 				(data[1] & 0x80) ? "yes" : "no",
848 				inet_ntop(AF_INET6, &data[2], addr, sizeof(addr)),
849 				data[18], val2str(data[19] & 0xF, ip6_addr_statuses));
850 		break;
851 
852 	case IPMI_LANP_IP6_DYNAMIC_ADDR:
853 		fprintf(file, "%s %d:\n"
854 				"    Source/Type:    %s\n"
855 				"    Address:        %s/%d\n"
856 				"    Status:         %s\n",
857 				pname, set,
858 				val2str(data[1] & 0xF, ip6_addr_sources),
859 				inet_ntop(AF_INET6, &data[2], addr, sizeof(addr)),
860 				data[18], val2str(data[19] & 0xF, ip6_addr_statuses));
861 		break;
862 
863 	case IPMI_LANP_IP6_STATIC_DUID:
864 	case IPMI_LANP_IP6_DYNAMIC_DUID:
865 		if (block == 0) {
866 			fprintf(file, "%s %d:\n"
867 				"    Length:   %d\n"
868 				"    Type:     %s\n",
869 				pname, set, data[2],
870 				val2str((data[3] << 8) + data[4], ip6_duid_types));
871 		}
872 		fprintf(file, "    %s\n", buf2str(&data[2], 16));
873 		break;
874 
875 	case IPMI_LANP_IP6_DHCP6_CFG_SUP:
876 	case IPMI_LANP_IP6_NDSLAAC_CFG_SUP:
877 		fprintf(file, "%s: %s\n",
878 				pname, val2str(data[0], ip6_cfg_sup_vals));
879 		break;
880 
881 	case IPMI_LANP_IP6_DHCP6_CFG:
882 		fprintf(file, "%s %d:\n", pname, set);
883 
884 		fprintf(file,
885 				"    SOL_MAX_DELAY:   %d\n"
886 				"    SOL_TIMEOUT:     %d\n"
887 				"    SOL_MAX_RT:      %d\n"
888 				"    REQ_TIMEOUT:     %d\n"
889 				"    REQ_MAX_RT:      %d\n"
890 				"    REQ_MAX_RC:      %d\n"
891 				"    CNF_MAX_DELAY:   %d\n"
892 				"    CNF_TIMEOUT:     %d\n"
893 				"    CNF_MAX_RT:      %d\n"
894 				"    CNF_MAX_RD:      %d\n"
895 				"    REN_TIMEOUT:     %d\n"
896 				"    REN_MAX_RT:      %d\n"
897 				"    REB_TIMEOUT:     %d\n"
898 				"    REB_MAX_RT:      %d\n"
899 				"    INF_MAX_DELAY:   %d\n"
900 				"    INF_TIMEOUT:     %d\n"
901 				"    INF_MAX_RT:      %d\n"
902 				"    REL_TIMEOUT:     %d\n"
903 				"    REL_MAX_RC:      %d\n"
904 				"    DEC_TIMEOUT:     %d\n"
905 				"    DEC_MAX_RC:      %d\n"
906 				"    HOP_COUNT_LIMIT: %d\n",
907 				data[2], data[3], data[4], data[5],
908 				data[6], data[7], data[8], data[9],
909 				data[10], data[11], data[12], data[13],
910 				data[14], data[15], data[16], data[17],
911 				data[20], data[21], data[22], data[23],
912 				data[24], data[25]);
913 		break;
914 
915 	case IPMI_LANP_IP6_ROUTER_CFG:
916 		fprintf(file, "%s:\n"
917 				"    Enable static router address:  %s\n"
918 				"    Enable dynamic router address: %s\n",
919 				pname,
920 				(data[0] & 1) ? "yes" : "no",
921 				(data[0] & 2) ? "yes" : "no");
922 		break;
923 
924 	case IPMI_LANP_IP6_STATIC_RTR1_ADDR:
925 	case IPMI_LANP_IP6_DYNAMIC_RTR_ADDR:
926 		if (p->specific == IPMI_LANP_IP6_STATIC_RTR1_ADDR) {
927 			pname = "IPv6 Static Router";
928 		} else {
929 			pname = "IPv6 Dynamic Router";
930 		}
931 
932 		fprintf(file, "%s %d:\n"
933 				"    Address: %s\n"
934 				"    MAC:     %s\n"
935 				"    Prefix:  %s/%d\n",
936 				pname, set,
937 				inet_ntop(AF_INET6, &data[1], addr, sizeof(addr)),
938 				mac2str(&data[18]),
939 				inet_ntop(AF_INET6, &data[27], pfx, sizeof(pfx)), data[25]);
940 		break;
941 
942 	case IPMI_LANP_IP6_NDSLAAC_CFG:
943 		fprintf(file, "%s %d:\n"
944 				"    MAX_RTR_SOLICITATION_DELAY: %d\n"
945 				"    RTR_SOLICITATION_INTERVAL:  %d\n"
946 				"    MAX_RTR_SOLICITATIONS:      %d\n"
947 				"    DupAddrDetectTransmits:     %d\n"
948 				"    MAX_MULTICAST_SOLICIT:      %d\n"
949 				"    MAX_UNICAST_SOLICIT:        %d\n"
950 				"    MAX_ANYCAST_DELAY_TIME:     %d\n"
951 				"    MAX_NEIGHBOR_ADVERTISEMENT: %d\n"
952 				"    REACHABLE_TIME:             %d\n"
953 				"    RETRANS_TIMER:              %d\n"
954 				"    DELAY_FIRST_PROBE_TIME:     %d\n"
955 				"    MAX_RANDOM_FACTOR:          %d\n"
956 				"    MIN_RANDOM_FACTOR:          %d\n",
957 				pname, set,
958 				data[2], data[3], data[4], data[5],
959 				data[6], data[7], data[8], data[9],
960 				data[10], data[11], data[12], data[13],
961 				data[14]);
962 		break;
963 
964 	default:
965 		fprintf(file, "%s: %d\n", pname, data[0]);
966 	}
967 
968 	return 0;
969 }
970 
971 static int
lanp_ip6_cfgp(void * priv,const struct ipmi_cfgp * p,const struct ipmi_cfgp_action * action,unsigned char * data)972 lanp_ip6_cfgp(void *priv, const struct ipmi_cfgp *p,
973 		const struct ipmi_cfgp_action *action, unsigned char *data)
974 {
975 	switch (action->type) {
976 	case CFGP_PARSE:
977 		return lanp_parse_cfgp(p, action->set, action->block,
978 				action->argc, action->argv, data);
979 
980 	case CFGP_GET:
981 		return lanp_get_cfgp(priv, p, action->set, action->block,
982 				data, action->quiet);
983 
984 	case CFGP_SET:
985 		return lanp_set_cfgp(priv, p, data);
986 
987 	case CFGP_SAVE:
988 		return lanp_save_cfgp(p, data, action->file);
989 
990 	case CFGP_PRINT:
991 		return lanp_print_cfgp(p, action->set, action->block,
992 				data, action->file);
993 
994 	default:
995 		return -1;
996 	}
997 
998 	return 0;
999 }
1000 
lanp_print_usage(int cmd)1001 static void lanp_print_usage(int cmd)
1002 {
1003 	if (cmd == LANP_CMD_ANY || cmd == LANP_CMD_HELP) {
1004 		printf("  help [command]\n");
1005 	}
1006 	if (cmd == LANP_CMD_ANY || cmd == LANP_CMD_SAVE) {
1007 		printf("  save <channel> [<parameter> [<set_sel> [<block_sel>]]]\n");
1008 	}
1009 	if (cmd == LANP_CMD_ANY || cmd == LANP_CMD_SET) {
1010 		printf("  set <channel> [nolock] <parameter> [<set_sel> [<block_sel>]] <values...>\n");
1011 	}
1012 	if (cmd == LANP_CMD_ANY || cmd == LANP_CMD_PRINT) {
1013 		printf("  print <channel> [<parameter> [<set_sel> [<block_sel>]]]\n");
1014 	}
1015 	if (cmd == LANP_CMD_ANY || cmd == LANP_CMD_LOCK) {
1016 		printf("  lock <channel>\n");
1017 	}
1018 	if (cmd == LANP_CMD_ANY || cmd == LANP_CMD_COMMIT) {
1019 		printf("  commit <channel>\n");
1020 	}
1021 	if (cmd == LANP_CMD_ANY || cmd == LANP_CMD_DISCARD) {
1022 		printf("  discard <channel>\n");
1023 	}
1024 	if (cmd == LANP_CMD_SAVE
1025 		|| cmd == LANP_CMD_PRINT
1026 		|| cmd == LANP_CMD_SET) {
1027 		printf("\n   available parameters:\n");
1028 		/* 'save' shall use 'write' filter, since it outputs a block
1029 		 * of 'set's */
1030 		ipmi_cfgp_usage(lan_cfgp,
1031 			sizeof(lan_cfgp)/sizeof(lan_cfgp[0]),
1032 			cmd != LANP_CMD_PRINT);
1033 	}
1034 }
1035 
1036 static int
lanp_lock(struct ipmi_lanp_priv * lp)1037 lanp_lock(struct ipmi_lanp_priv *lp)
1038 {
1039 	unsigned char byte = 1;
1040 
1041 	return ipmi_set_lanp(lp, 0, &byte);
1042 }
1043 
1044 static int
lanp_discard(struct ipmi_lanp_priv * lp)1045 lanp_discard(struct ipmi_lanp_priv *lp)
1046 {
1047 	unsigned char byte = 0;
1048 
1049 	return ipmi_set_lanp(lp, 0, &byte);
1050 }
1051 
1052 static int
lanp_commit(struct ipmi_lanp_priv * lp)1053 lanp_commit(struct ipmi_lanp_priv *lp)
1054 {
1055 	unsigned char byte = 2;
1056 	int ret;
1057 
1058 	ret = ipmi_set_lanp(lp, 0, &byte);
1059 	if (ret == 0) {
1060 		ret = lanp_discard(lp);
1061 	}
1062 
1063 	return ret;
1064 }
1065 
1066 int
ipmi_lan6_main(struct ipmi_intf * intf,int argc,char ** argv)1067 ipmi_lan6_main(struct ipmi_intf *intf, int argc, char **argv)
1068 {
1069 	struct ipmi_cfgp_ctx ctx;
1070 	struct ipmi_cfgp_sel sel;
1071 	struct ipmi_lanp_priv lp;
1072 	int cmd;
1073 	int chan;
1074 	int nolock = 0;
1075 	int ret;
1076 
1077 	if (argc == 0) {
1078 		lanp_print_usage(LANP_CMD_ANY);
1079 		return 0;
1080 	}
1081 
1082 	cmd = str2val(argv[0], ip6_command_vals);
1083 	if (cmd == LANP_CMD_ANY) {
1084 		lanp_print_usage(cmd);
1085 		return -1;
1086 	}
1087 
1088 	if (cmd == LANP_CMD_HELP) {
1089 		if (argc == 1) {
1090 			cmd = LANP_CMD_ANY;
1091 		} else {
1092 			cmd = str2val(argv[1], ip6_command_vals);
1093 		}
1094 
1095 		lanp_print_usage(cmd);
1096 		return 0;
1097 	}
1098 
1099 	/*
1100 	 * the rest commands expect channel number
1101 	 * with the exception of 'get' and 'print'
1102 	 */
1103 	if (argc == 1) {
1104 		if (cmd == LANP_CMD_SAVE || cmd == LANP_CMD_PRINT) {
1105 			chan = find_lan_channel(intf, 1);
1106 			if (chan == 0) {
1107 				lprintf(LOG_ERR, "No LAN channel found");
1108 				return -1;
1109 			}
1110 		} else {
1111 			lanp_print_usage(cmd);
1112 			return -1;
1113 		}
1114 
1115 		argc -= 1;
1116 		argv += 1;
1117 	} else {
1118 		if (str2int(argv[1], &chan) != 0) {
1119 			lprintf(LOG_ERR, "Invalid channel: %s", argv[1]);
1120 			return -1;
1121 		}
1122 
1123 		argc -= 2;
1124 		argv += 2;
1125 
1126 		if (cmd == LANP_CMD_SET) {
1127 			if (argc && !strcasecmp(argv[0], "nolock")) {
1128 				nolock = 1;
1129 
1130 				argc -= 1;
1131 				argv += 1;
1132 			}
1133 		}
1134 
1135 	}
1136 
1137 	lp.intf = intf;
1138 	lp.channel = chan;
1139 
1140 	/*
1141 	 * lock/commit/discard commands do not require parsing
1142 	 * of parameter selection
1143 	 */
1144 
1145 	switch (cmd) {
1146 	case LANP_CMD_LOCK:
1147 		lprintf(LOG_NOTICE, "Lock parameter(s)...");
1148 		return lanp_lock(&lp);
1149 
1150 	case LANP_CMD_COMMIT:
1151 		lprintf(LOG_NOTICE, "Commit parameter(s)...");
1152 		return lanp_commit(&lp);
1153 
1154 	case LANP_CMD_DISCARD:
1155 		lprintf(LOG_NOTICE, "Discard parameter(s)...");
1156 		return lanp_discard(&lp);
1157 	}
1158 
1159 	/*
1160 	 * initialize configuration context and parse parameter selection
1161 	 */
1162 
1163 	ipmi_cfgp_init(&ctx, lan_cfgp,
1164 		sizeof(lan_cfgp)/sizeof(lan_cfgp[0]), "lan6 set nolock",
1165 		lanp_ip6_cfgp, &lp);
1166 
1167 	ret = ipmi_cfgp_parse_sel(&ctx, argc, (const char **)argv, &sel);
1168 	if (ret == -1) {
1169 		lanp_print_usage(cmd);
1170 		ipmi_cfgp_uninit(&ctx);
1171 		return -1;
1172 	}
1173 
1174 	argc -= ret;
1175 	argv += ret;
1176 
1177 	/*
1178 	 * handle the rest commands
1179 	 */
1180 
1181 	switch (cmd) {
1182 	case LANP_CMD_SAVE:
1183 	case LANP_CMD_PRINT:
1184 		lprintf(LOG_NOTICE, "Getting parameter(s)...");
1185 
1186 		ret = ipmi_cfgp_get(&ctx, &sel);
1187 		if (ret != 0) {
1188 			break;
1189 		}
1190 
1191 		if (cmd == LANP_CMD_SAVE) {
1192 			static char cmd[20];
1193 			FILE *out = stdout;
1194 			snprintf(cmd, sizeof(cmd) - 1, "lan6 set %d nolock",
1195 				lp.channel);
1196 			cmd[sizeof(cmd) - 1] = '\0';
1197 			ctx.cmdname = cmd;
1198 			fprintf(out, "lan6 lock %d\n", lp.channel);
1199 			ret = ipmi_cfgp_save(&ctx, &sel, out);
1200 			fprintf(out, "lan6 commit %d\nlan6 discard %d\nexit\n",
1201 				lp.channel, lp.channel);
1202 		} else {
1203 			ret = ipmi_cfgp_print(&ctx, &sel, stdout);
1204 		}
1205 		break;
1206 
1207 	case LANP_CMD_SET:
1208 		ret = ipmi_cfgp_parse_data(&ctx, &sel, argc,
1209 			(const char **)argv);
1210 		if (ret != 0) {
1211 			break;
1212 		}
1213 
1214 		lprintf(LOG_NOTICE, "Setting parameter(s)...");
1215 
1216 		if (!nolock) {
1217 			ret = lanp_lock(&lp);
1218 			if (ret != 0) {
1219 				break;
1220 			}
1221 		}
1222 
1223 		ret = ipmi_cfgp_set(&ctx, &sel);
1224 		if (!nolock) {
1225 			if (ret == 0) {
1226 				ret = lanp_commit(&lp);
1227 			} else {
1228 				lanp_discard(&lp);
1229 			}
1230 		}
1231 		break;
1232 	}
1233 
1234 	/*
1235 	 * free allocated memory
1236 	 */
1237 	ipmi_cfgp_uninit(&ctx);
1238 
1239 	return ret;
1240 }
1241