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