1 /*
2 * tipc-config.c: TIPC configuration tool
3 *
4 * Copyright (c) 2004-2006, Ericsson AB
5 * Copyright (c) 2005-2006, Wind River Systems
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the names of the copyright holders nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <getopt.h>
37 #include <unistd.h>
38 #include <poll.h>
39 #include <string.h>
40 #include <fcntl.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <linux/tipc.h>
46 #include <linux/tipc_config.h>
47 #include <linux/genetlink.h>
48
49 /* typedefs */
50
51 typedef void (*VOIDFUNCPTR) ();
52
53 /* constants */
54
55 #define MAX_COMMANDS 8
56 #define MAX_TLVS_SPACE 33000 /* must be a multiple of 4 bytes */
57
58 /* local variables */
59
60 static int verbose = 0;
61 static int interactive = 0;
62 static __u32 dest = 0;
63 static __u32 tlv_area[MAX_TLVS_SPACE / sizeof(__u32)];
64 static __u32 tlv_list_area[MAX_TLVS_SPACE / sizeof(__u32)];
65
66 /* forward declarations */
67
68 static char usage[];
69
70 /* macros */
71
72 #define cprintf(fmt, arg...) do { if (verbose) printf(fmt, ##arg); } while (0)
73
74 #define fatal(fmt, arg...) do { printf(fmt, ##arg); exit(EXIT_FAILURE); } while (0)
75
76 #define confirm(fmt, arg...) do { \
77 char c; \
78 if (interactive) { \
79 printf(fmt, ##arg); \
80 scanf(" %c", &c); /* leading blank skips whitespace */ \
81 if ((c != '\n') && (c != 'Y') && (c != 'y')) { \
82 printf("Exiting...\n"); \
83 exit(EXIT_SUCCESS); \
84 } \
85 } \
86 } while (0)
87
88 /* local variables */
89
90 static char *err_string[] = {
91 "incorrect message format",
92 "must be network administrator to perform operation",
93 "must be zone master to perform operation",
94 "remote management not enabled on destination node",
95 "operation not supported",
96 "invalid argument"
97 };
98
99 /******************************************************************************
100 *
101 * Utility routines used in executing command options
102 *
103 */
104
delimit(int val,int min,int max)105 static inline int delimit(int val, int min, int max)
106 {
107 if (val > max)
108 return max;
109 if (val < min)
110 return min;
111 return val;
112 }
113
own_node(void)114 static __u32 own_node(void)
115 {
116 struct sockaddr_tipc addr;
117 socklen_t sz = sizeof(addr);
118 int sd;
119
120 sd = socket(AF_TIPC, SOCK_RDM, 0);
121 if (sd < 0)
122 fatal("TIPC module not installed\n");
123 if (getsockname(sd, (struct sockaddr *)&addr, &sz) < 0)
124 fatal("failed to get TIPC socket address\n");
125 close(sd);
126 return addr.addr.id.node;
127 }
128
addr2str(__u32 addr)129 static const char *addr2str(__u32 addr)
130 {
131 static char addr_area[2][16];
132 static int addr_crs = 0;
133
134 addr_crs = !addr_crs;
135 sprintf(&addr_area[addr_crs][0], "<%u.%u.%u>",
136 tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
137 return &addr_area[addr_crs][0];
138 }
139
for_dest(void)140 static const char *for_dest(void)
141 {
142 static char addr_area[30];
143
144 if (dest == own_node())
145 return "";
146 sprintf(addr_area, " for node %s", addr2str(dest));
147 return addr_area;
148 }
149
get_arg(char ** args)150 char *get_arg(char **args)
151 {
152 char *ret;
153 char *comma;
154
155 ret = *args;
156 comma = strchr(ret, ',');
157 if (comma) {
158 *comma = '\0';
159 *args = comma + 1;
160 }
161 else
162 *args = NULL;
163 return ret;
164 }
165
str2addr(char * str)166 static __u32 str2addr(char *str)
167 {
168 uint z, c, n;
169 char dummy;
170
171 if (sscanf(str, "%u.%u.%u%c", &z, &c, &n, &dummy) != 3)
172 fatal("invalid network address, use syntax: Z.C.N\n");
173 if ((z != delimit(z, 0, 255)) ||
174 (c != delimit(c, 0, 4095)) ||
175 (n != delimit(n, 0, 4095)))
176 fatal("network address field value(s) too large\n");
177 return tipc_addr(z, c, n);
178 }
179
180
181 /******************************************************************************
182 *
183 * Routines used to exchange messages over Netlink sockets
184 *
185 */
186
187 #define NLA_SIZE(type) (NLA_HDRLEN + NLA_ALIGN(sizeof(type)))
188
189 #define nla_for_each_attr(pos, head, len, rem) \
190 for (pos = head, rem = len; nla_ok(pos, rem); pos = nla_next(pos, &(rem)))
191
nla_data(const struct nlattr * nla)192 static inline void *nla_data(const struct nlattr *nla)
193 {
194 return (char *) nla + NLA_HDRLEN;
195 }
196
nla_ok(const struct nlattr * nla,int remaining)197 static inline int nla_ok(const struct nlattr *nla, int remaining)
198 {
199 return remaining >= sizeof(*nla) &&
200 nla->nla_len >= sizeof(*nla) &&
201 nla->nla_len <= remaining;
202 }
203
nla_next(const struct nlattr * nla,int * remaining)204 static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining)
205 {
206 int totlen = NLA_ALIGN(nla->nla_len);
207
208 *remaining -= totlen;
209 return (struct nlattr *) ((char *) nla + totlen);
210 }
211
nla_put_string(struct nlattr * nla,int type,const char * str)212 static inline int nla_put_string(struct nlattr *nla, int type, const char *str)
213 {
214 int attrlen = strlen(str) + 1;
215
216 nla->nla_len = NLA_HDRLEN + attrlen;
217 nla->nla_type = type;
218 memcpy(nla_data(nla), str, attrlen);
219
220 return NLA_HDRLEN + NLA_ALIGN(attrlen);
221 }
222
nla_get_u16(struct nlattr * nla)223 static inline __u16 nla_get_u16(struct nlattr *nla)
224 {
225 return *(__u16 *) nla_data(nla);
226 }
227
write_uninterrupted(int sk,const char * buf,int len)228 static int write_uninterrupted(int sk, const char *buf, int len)
229 {
230 int c;
231
232 while ((c = write(sk, buf, len)) < len) {
233 if (c == -1) {
234 if (errno == EINTR)
235 continue;
236 return -1;
237 }
238
239 buf += c;
240 len -= c;
241 }
242
243 return 0;
244 }
245
genetlink_call(__u16 family_id,__u8 cmd,void * header,size_t header_len,void * request,size_t request_len,void * reply,size_t reply_len)246 static int genetlink_call(__u16 family_id, __u8 cmd, void *header,
247 size_t header_len, void *request, size_t request_len,
248 void *reply, size_t reply_len)
249 {
250 struct msg {
251 struct nlmsghdr n;
252 struct genlmsghdr g;
253 char payload[0];
254 };
255
256 struct msg *request_msg;
257 struct msg *reply_msg;
258 int request_msg_size;
259 int reply_msg_size;
260
261 struct sockaddr_nl local;
262 struct pollfd pfd;
263 int sndbuf = 32*1024; /* 32k */
264 int rcvbuf = 32*1024; /* 32k */
265 int len;
266 int sk;
267
268 /*
269 * Prepare request/reply messages
270 */
271 request_msg_size = NLMSG_LENGTH(GENL_HDRLEN + header_len + request_len);
272 request_msg = malloc(request_msg_size);
273 request_msg->n.nlmsg_len = request_msg_size;
274 request_msg->n.nlmsg_type = family_id;
275 request_msg->n.nlmsg_flags = NLM_F_REQUEST;
276 request_msg->n.nlmsg_seq = 0;
277 request_msg->n.nlmsg_pid = getpid();
278 request_msg->g.cmd = cmd;
279 request_msg->g.version = 0;
280 if (header_len)
281 memcpy(&request_msg->payload[0], header, header_len);
282 if (request_len)
283 memcpy(&request_msg->payload[header_len], request, request_len);
284
285 reply_msg_size = NLMSG_LENGTH(GENL_HDRLEN + header_len + reply_len);
286 reply_msg = malloc(reply_msg_size);
287
288 /*
289 * Create socket
290 */
291 memset(&local, 0, sizeof(local));
292 local.nl_family = AF_NETLINK;
293
294 if ((sk = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_GENERIC)) == -1)
295 fatal("error creating Netlink socket\n");
296
297 if ((bind(sk, (struct sockaddr*)&local, sizeof(local)) == -1) ||
298 (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) == -1) ||
299 (setsockopt(sk, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) == -1)) {
300 fatal("error creating Netlink socket\n");
301 }
302
303 /*
304 * Send request
305 */
306 if (write_uninterrupted(sk, (char*)request_msg, request_msg_size) < 0)
307 fatal("error sending message via Netlink\n");
308
309 /*
310 * Wait for reply
311 */
312 pfd.fd = sk;
313 pfd.events = ~POLLOUT;
314 if ((poll(&pfd, 1, 3000) != 1) || !(pfd.revents & POLLIN))
315 fatal("no reply detected from Netlink\n");
316
317 /*
318 * Read reply
319 */
320 len = recv(sk, (char*)reply_msg, reply_msg_size, 0);
321 if (len < 0)
322 fatal("error receiving reply message via Netlink\n");
323
324 close(sk);
325
326 /*
327 * Validate response
328 */
329 if (!NLMSG_OK(&reply_msg->n, len))
330 fatal("invalid reply message received via Netlink\n");
331
332 if (reply_msg->n.nlmsg_type == NLMSG_ERROR) {
333 len = -1;
334 goto out;
335 }
336
337 if ((request_msg->n.nlmsg_type != reply_msg->n.nlmsg_type) ||
338 (request_msg->n.nlmsg_seq != reply_msg->n.nlmsg_seq))
339 fatal("unexpected message received via Netlink\n");
340
341 /*
342 * Copy reply header
343 */
344 len -= NLMSG_LENGTH(GENL_HDRLEN);
345 if (len < header_len)
346 fatal("too small reply message received via Netlink\n");
347 if (header_len > 0)
348 memcpy(header, &reply_msg->payload[0], header_len);
349
350 /*
351 * Copy reply payload
352 */
353 len -= header_len;
354 if (len > reply_len)
355 fatal("reply message too large to copy\n");
356 if (len > 0)
357 memcpy(reply, &reply_msg->payload[header_len], len);
358
359 out:
360 free(request_msg);
361 free(reply_msg);
362
363 return len;
364 }
365
get_genl_family_id(const char * name)366 static int get_genl_family_id(const char* name)
367 {
368 struct nlattr_family_name {
369 char value[GENL_NAMSIZ];
370 };
371
372 struct nlattr_family_id {
373 __u16 value;
374 };
375
376 /*
377 * Create request/reply buffers
378 *
379 * Note that the reply buffer is larger than necessary in case future
380 * versions of Netlink return additional protocol family attributes
381 */
382 char request[NLA_SIZE(struct nlattr_family_name)];
383 int request_len = nla_put_string((struct nlattr *)request, CTRL_ATTR_FAMILY_NAME, name);
384
385 char reply[256];
386 int reply_len = sizeof(reply);
387
388 /*
389 * Call control service
390 */
391 int len = genetlink_call(GENL_ID_CTRL, CTRL_CMD_GETFAMILY,
392 0, 0,
393 request, request_len,
394 reply, reply_len);
395
396 if (len == -1)
397 return -1;
398
399 /*
400 * Parse reply
401 */
402 struct nlattr *head = (struct nlattr *) reply;
403 struct nlattr *nla;
404 int rem;
405
406 nla_for_each_attr(nla, head, len, rem) {
407 if (nla->nla_type == CTRL_ATTR_FAMILY_ID)
408 return nla_get_u16(nla);
409 }
410
411 if (rem > 0)
412 fatal("%d bytes leftover after parsing Netlink attributes\n", rem);
413
414 return -1;
415 }
416
do_command_netlink(__u16 cmd,void * req_tlv,__u32 req_tlv_space,void * rep_tlv,__u32 rep_tlv_space)417 static int do_command_netlink(__u16 cmd, void *req_tlv, __u32 req_tlv_space,
418 void *rep_tlv, __u32 rep_tlv_space)
419 {
420 struct tipc_genlmsghdr header;
421 int family_id;
422 int len;
423
424 /*
425 * Request header
426 */
427 header.dest = dest;
428 header.cmd = cmd;
429
430 /*
431 * Get TIPC family id
432 */
433 if ((family_id = get_genl_family_id(TIPC_GENL_NAME)) == -1)
434 fatal("no Netlink service registered for %s\n", TIPC_GENL_NAME);
435
436 /*
437 * Call control service
438 */
439 len = genetlink_call(family_id, TIPC_GENL_CMD,
440 &header, sizeof(header),
441 req_tlv, req_tlv_space,
442 rep_tlv, rep_tlv_space);
443
444 return len;
445 }
446
447 /******************************************************************************
448 *
449 * Routines used to exchange messages over TIPC sockets
450 *
451 */
452
do_command_tipc(__u16 cmd,void * req_tlv,__u32 req_tlv_space,void * rep_tlv,__u32 rep_tlv_space)453 static int do_command_tipc(__u16 cmd, void *req_tlv, __u32 req_tlv_space,
454 void *rep_tlv, __u32 rep_tlv_space)
455 {
456 struct {
457 struct tipc_cfg_msg_hdr hdr;
458 char buf[MAX_TLVS_SPACE];
459 } req, ans;
460 int msg_space;
461 int tsd;
462 struct sockaddr_tipc tipc_dest;
463 int imp = TIPC_CRITICAL_IMPORTANCE;
464 struct pollfd pfd;
465 int pollres;
466
467 if ((tsd = socket(AF_TIPC, SOCK_RDM, 0)) < 0)
468 fatal("TIPC module not installed\n");
469
470 msg_space = TCM_SET(&req.hdr, cmd, TCM_F_REQUEST,
471 req_tlv, req_tlv_space);
472
473 setsockopt(tsd, SOL_TIPC, TIPC_IMPORTANCE, &imp, sizeof(imp));
474
475 tipc_dest.family = AF_TIPC;
476 tipc_dest.addrtype = TIPC_ADDR_NAME;
477 tipc_dest.addr.name.name.type = TIPC_CFG_SRV;
478 tipc_dest.addr.name.name.instance = dest;
479 tipc_dest.addr.name.domain = 0;
480
481 if (sendto(tsd, &req, msg_space, 0,
482 (struct sockaddr *)&tipc_dest, sizeof(tipc_dest)) < 0)
483 fatal("unable to send command to node %s\n", addr2str(dest));
484
485 /* Wait for response message */
486
487 pfd.events = 0xffff & ~POLLOUT;
488 pfd.fd = tsd;
489 pollres = poll(&pfd, 1, 3000);
490 if ((pollres < 0) || !(pfd.revents & POLLIN))
491 fatal("no reply detected from TIPC\n");
492 msg_space = recv(tsd, &ans, sizeof(ans), 0);
493 if (msg_space < 0)
494 fatal("error receiving reply message via TIPC\n");
495
496 /* Validate response message */
497
498 if ((msg_space < TCM_SPACE(0)) || (ntohl(ans.hdr.tcm_len) > msg_space))
499 fatal("invalid reply message received via TIPC\n");
500 if ((ntohs(ans.hdr.tcm_type) != cmd) ||
501 (ntohs(ans.hdr.tcm_flags) != 0))
502 fatal("unexpected message received via TIPC\n");
503
504 msg_space = ntohl(ans.hdr.tcm_len) - TCM_SPACE(0);
505 if (msg_space > rep_tlv_space)
506 fatal("reply message too large to copy\n");
507 memcpy(rep_tlv, ans.buf, msg_space);
508 return msg_space;
509 }
510
511
512 /******************************************************************************
513 *
514 * Routines used to process commands requested by user
515 *
516 */
517
do_command(__u16 cmd,void * req_tlv,__u32 req_tlv_space,void * rep_tlv,__u32 rep_tlv_space)518 static __u32 do_command(__u16 cmd, void *req_tlv, __u32 req_tlv_space,
519 void *rep_tlv, __u32 rep_tlv_space)
520 {
521 int rep_len;
522
523 if (dest == own_node())
524 rep_len = do_command_netlink(cmd, req_tlv, req_tlv_space,
525 rep_tlv, rep_tlv_space);
526 else
527 rep_len = do_command_tipc(cmd, req_tlv, req_tlv_space,
528 rep_tlv, rep_tlv_space);
529
530 if (TLV_CHECK(rep_tlv, rep_len, TIPC_TLV_ERROR_STRING)) {
531 char *c = (char *)TLV_DATA(rep_tlv);
532 char code = *c;
533 char max_code = sizeof(err_string)/sizeof(err_string[0]);
534
535 if (code & 0x80) {
536 code &= 0x7F;
537 printf((code < max_code)
538 ? err_string[(int)code] : "unknown error");
539 c++;
540 }
541 fatal("%s\n", c);
542 }
543
544 return rep_len;
545 }
546
do_get_unsigned(__u16 cmd)547 static __u32 do_get_unsigned(__u16 cmd)
548 {
549 int tlv_space;
550 __u32 value;
551
552 tlv_space = do_command(cmd, NULL, 0, tlv_area, sizeof(tlv_area));
553
554 if (!TLV_CHECK(tlv_area, tlv_space, TIPC_TLV_UNSIGNED))
555 fatal("corrupted reply message\n");
556
557 value = *(__u32 *)TLV_DATA(tlv_area);
558 return ntohl(value);
559 }
560
do_set_unsigned(char * args,__u16 cmd,char * attr_name,char * attr_warn)561 static void do_set_unsigned(char *args, __u16 cmd, char *attr_name,
562 char *attr_warn)
563 {
564 __u32 attr_val;
565 __u32 attr_val_net;
566 int tlv_space;
567 char dummy;
568
569 if (sscanf(args, "%u%c", &attr_val, &dummy) != 1)
570 fatal("invalid numeric argument for %s\n", attr_name);
571
572 confirm("set %s to %u%s?%s [Y/n]\n", attr_name, attr_val,
573 for_dest(), attr_warn);
574
575 attr_val_net = htonl(attr_val);
576 tlv_space = TLV_SET(tlv_area, TIPC_TLV_UNSIGNED,
577 &attr_val_net, sizeof(attr_val_net));
578 do_command(cmd, tlv_area, tlv_space, tlv_area, sizeof(tlv_area));
579
580 cprintf("%s%s now set to %u\n", attr_name, for_dest(), attr_val);
581 }
582
set_node_addr(char * args)583 static void set_node_addr(char *args)
584 {
585 __u32 new_addr;
586 __u32 new_addr_net;
587 int tlv_space;
588
589 if (!*args) {
590 do_command(TIPC_CMD_NOOP, NULL, 0, tlv_area, sizeof(tlv_area));
591 printf("node address: %s\n", addr2str(dest));
592 return;
593 }
594
595 new_addr = str2addr(args);
596
597 confirm("change node address%s to %s? "
598 "(this will delete all links) [Y/n]\n",
599 for_dest(), addr2str(new_addr));
600
601 new_addr_net = htonl(new_addr);
602 tlv_space = TLV_SET(tlv_area, TIPC_TLV_NET_ADDR,
603 &new_addr_net, sizeof(new_addr_net));
604 do_command(TIPC_CMD_SET_NODE_ADDR, tlv_area, tlv_space,
605 tlv_area, sizeof(tlv_area));
606
607 cprintf("node address%s now set to %s\n",
608 for_dest(), addr2str(new_addr));
609 dest = new_addr;
610 }
611
set_remote_mng(char * args)612 static void set_remote_mng(char *args)
613 {
614 __u32 attr_val;
615 __u32 attr_val_net;
616 int tlv_space;
617
618 if (!*args) {
619 printf("remote management%s: %s\n", for_dest(),
620 do_get_unsigned(TIPC_CMD_GET_REMOTE_MNG) ?
621 "enabled" : "disabled");
622 return;
623 }
624
625 if (!strcmp(args, "enable"))
626 attr_val = 1;
627 else if (!strcmp(args, "disable"))
628 attr_val = 0;
629 else
630 fatal("invalid argument for remote management\n");
631
632 confirm("%s remote management%s? [Y/n]\n",
633 attr_val ? "enable" : "disable", for_dest());
634
635 attr_val_net = htonl(attr_val);
636 tlv_space = TLV_SET(tlv_area, TIPC_TLV_UNSIGNED,
637 &attr_val_net, sizeof(attr_val_net));
638 do_command(TIPC_CMD_SET_REMOTE_MNG, tlv_area, tlv_space,
639 tlv_area, sizeof(tlv_area));
640
641 cprintf("remote management%s %s\n", for_dest(),
642 attr_val ? "enabled" : "disabled");
643 }
644
set_max_ports(char * args)645 static void set_max_ports(char *args)
646 {
647 if (!*args)
648 printf("maximum allowed ports%s: %u\n", for_dest(),
649 do_get_unsigned(TIPC_CMD_GET_MAX_PORTS));
650 else
651 do_set_unsigned(args, TIPC_CMD_SET_MAX_PORTS, "max ports",
652 " (this will restart TIPC)");
653 }
654
set_max_publ(char * args)655 static void set_max_publ(char *args)
656 {
657 if (!*args)
658 printf("maximum allowed publications%s: %u\n", for_dest(),
659 do_get_unsigned(TIPC_CMD_GET_MAX_PUBL));
660 else
661 do_set_unsigned(args, TIPC_CMD_SET_MAX_PUBL,
662 "max publications", "");
663 }
664
set_max_subscr(char * args)665 static void set_max_subscr(char *args)
666 {
667 if (!*args)
668 printf("maximum allowed subscriptions%s: %u\n", for_dest(),
669 do_get_unsigned(TIPC_CMD_GET_MAX_SUBSCR));
670 else
671 do_set_unsigned(args, TIPC_CMD_SET_MAX_SUBSCR,
672 "max subscriptions", "");
673 }
674
set_max_zones(char * args)675 static void set_max_zones(char *args)
676 {
677 if (!*args)
678 printf("maximum allowed zones%s: %u\n", for_dest(),
679 do_get_unsigned(TIPC_CMD_GET_MAX_ZONES));
680 else
681 do_set_unsigned(args, TIPC_CMD_SET_MAX_ZONES, "max zones",
682 " (this will reset all links)");
683 }
684
set_max_clusters(char * args)685 static void set_max_clusters(char *args)
686 {
687 if (!*args)
688 printf("maximum allowed clusters%s: %u\n", for_dest(),
689 do_get_unsigned(TIPC_CMD_GET_MAX_CLUSTERS));
690 else
691 do_set_unsigned(args, TIPC_CMD_SET_MAX_CLUSTERS, "max clusters",
692 " (this will reset all links)");
693 }
694
set_max_nodes(char * args)695 static void set_max_nodes(char *args)
696 {
697 if (!*args)
698 printf("maximum allowed nodes%s: %u\n", for_dest(),
699 do_get_unsigned(TIPC_CMD_GET_MAX_NODES));
700 else
701 do_set_unsigned(args, TIPC_CMD_SET_MAX_NODES, "max nodes",
702 " (this will reset all links)");
703 }
704
set_max_slaves(char * args)705 static void set_max_slaves(char *args)
706 {
707 if (!*args)
708 printf("maximum allowed secondary nodes%s: %u\n", for_dest(),
709 do_get_unsigned(TIPC_CMD_GET_MAX_SLAVES));
710 else
711 do_set_unsigned(args, TIPC_CMD_SET_MAX_SLAVES, "max secondary nodes",
712 " (this will reset all links)");
713 }
714
set_netid(char * args)715 static void set_netid(char *args)
716 {
717 if (!*args)
718 printf("current network id%s: %u\n", for_dest(),
719 do_get_unsigned(TIPC_CMD_GET_NETID));
720 else
721 do_set_unsigned(args, TIPC_CMD_SET_NETID, "network identity",
722 " (this will reset all links)");
723 }
724
get_nodes(char * args)725 static void get_nodes(char *args)
726 {
727 int tlv_space;
728 __u32 domain;
729 __u32 domain_net;
730 struct tlv_list_desc tlv_list;
731 struct tipc_node_info *node_info;
732
733 domain = (*args != 0) ? str2addr(args) : 0;
734 domain_net = htonl(domain);
735 tlv_space = TLV_SET(tlv_area, TIPC_TLV_NET_ADDR,
736 &domain_net, sizeof(domain_net));
737 tlv_space = do_command(TIPC_CMD_GET_NODES, tlv_area, tlv_space,
738 tlv_area, sizeof(tlv_area));
739
740 printf("Nodes known%s%s%s:\n", for_dest(),
741 (domain ? " within domain " : ""),
742 (domain ? addr2str(domain) : ""));
743
744 if (!tlv_space) {
745 printf("None\n");
746 return;
747 }
748
749 TLV_LIST_INIT(&tlv_list, tlv_area, tlv_space);
750 while (!TLV_LIST_EMPTY(&tlv_list)) {
751 if (!TLV_LIST_CHECK(&tlv_list, TIPC_TLV_NODE_INFO))
752 fatal("corrupted reply message\n");
753 node_info = (struct tipc_node_info *)TLV_LIST_DATA(&tlv_list);
754 printf("%s: %s\n", addr2str(ntohl(node_info->addr)),
755 ntohl(node_info->up) ? "up" : "down");
756 TLV_LIST_STEP(&tlv_list);
757 }
758 }
759
760 /**
761 * do_these_links - perform operation on specified set of links
762 * @funcToRun: operation to be performed on link
763 * @domain: network domain of interest (0.0.0 if not used)
764 * @str: link name pattern of interest (NULL if not used)
765 * @vname: name of the parameter being set (optional arg to 'funcToRun')
766 * @cmd: command to execute (optional arg to 'funcToRun')
767 * @val: new value to be set (optional arg to 'funcToRun')
768 *
769 * This routine first retrieves the names of all links in the specified
770 * network domain, eliminates those that don't match the specified search
771 * pattern, and then performs the requestion operation on each remaining link.
772 */
773
do_these_links(VOIDFUNCPTR funcToRun,__u32 domain,const char * str,const char * vname,int cmd,int val)774 static void do_these_links(VOIDFUNCPTR funcToRun, __u32 domain, const char *str,
775 const char *vname, int cmd, int val)
776 {
777 int tlv_space;
778 int numLinks = 0;
779 __u32 domain_net;
780 struct tlv_list_desc tlv_list;
781 struct tipc_link_info *local_link_info;
782
783 domain_net = htonl(domain);
784 tlv_space = TLV_SET(tlv_list_area, TIPC_TLV_NET_ADDR,
785 &domain_net, sizeof(domain_net));
786 tlv_space = do_command(TIPC_CMD_GET_LINKS, tlv_list_area, tlv_space,
787 tlv_list_area, sizeof(tlv_list_area));
788
789 TLV_LIST_INIT(&tlv_list, tlv_list_area, tlv_space);
790
791 while (!TLV_LIST_EMPTY(&tlv_list)) {
792 if (!TLV_LIST_CHECK(&tlv_list, TIPC_TLV_LINK_INFO))
793 fatal("corrupted reply message in do_these_links\n");
794 local_link_info = (struct tipc_link_info *)TLV_LIST_DATA(&tlv_list);
795 if ((str == NULL) ||
796 (strstr(local_link_info->str, str) != NULL)) {
797 funcToRun(local_link_info->str, local_link_info->up,
798 vname, cmd, val);
799 numLinks++;
800 }
801 TLV_LIST_STEP(&tlv_list);
802 }
803
804 if (numLinks == 0) {
805 if (str == NULL)
806 printf("No links found\n");
807 else
808 printf("No links found matching pattern '%s'\n", str);
809 }
810 }
811
get_link(char * linkName,__u32 up)812 static void get_link(char *linkName, __u32 up)
813 {
814 printf("%s: %s\n", linkName, ntohl(up) ? "up" : "down");
815 }
816
get_linkset(char * args)817 static void get_linkset(char *args)
818 {
819 char *strp = NULL; /* list all links by default */
820 __u32 domain = 0;
821
822 if (*args != 0) {
823 if (args[0] == '?')
824 strp = args + 1; /* list links matching pattern */
825 else
826 domain = str2addr(args);/* list links in domain */
827 }
828
829 printf("Links%s%s%s:\n", for_dest(),
830 (domain ? " within domain " : ""),
831 (domain ? addr2str(domain) : ""));
832
833 do_these_links(get_link, domain, strp, "", 0, 0);
834 }
835
show_link_stats(char * linkName)836 static void show_link_stats(char *linkName)
837 {
838 int tlv_space;
839
840 tlv_space = TLV_SET(tlv_area, TIPC_TLV_LINK_NAME,
841 linkName, TIPC_MAX_LINK_NAME);
842 tlv_space = do_command(TIPC_CMD_SHOW_LINK_STATS, tlv_area, tlv_space,
843 tlv_area, sizeof(tlv_area));
844
845 if (!TLV_CHECK(tlv_area, tlv_space, TIPC_TLV_ULTRA_STRING))
846 fatal("corrupted reply message in show_link_stats\n");
847
848 printf("%s\n", (char *)TLV_DATA(tlv_area));
849 }
850
show_linkset_stats(char * args)851 static void show_linkset_stats(char *args)
852 {
853 if (dest != own_node())
854 printf("Link statistics%s\n", for_dest());
855
856 if (*args == 0) /* show for all links */
857 do_these_links(show_link_stats, 0, NULL, NULL, 0, 0);
858 else if (args[0] == '?') /* show for all links matching pattern */
859 do_these_links(show_link_stats, 0, args+1, NULL, 0, 0);
860 else /* show for specified link */
861 show_link_stats(args);
862 }
863
reset_link_stats(char * linkName)864 static void reset_link_stats(char *linkName)
865 {
866 int tlv_space;
867
868 tlv_space = TLV_SET(tlv_area, TIPC_TLV_LINK_NAME,
869 linkName, TIPC_MAX_LINK_NAME);
870 tlv_space = do_command(TIPC_CMD_RESET_LINK_STATS, tlv_area, tlv_space,
871 tlv_area, sizeof(tlv_area));
872
873 cprintf("Link %s statistics reset\n", linkName);
874 }
875
reset_linkset_stats(char * args)876 static void reset_linkset_stats(char *args)
877 {
878 if (args[0] == '?')
879 do_these_links(reset_link_stats, 0, args+1, NULL, 0, 0);
880 else
881 reset_link_stats(args);
882 }
883
884
show_name_table(char * args)885 static void show_name_table(char *args)
886 {
887 int tlv_space;
888 __u32 depth;
889 __u32 type;
890 __u32 lowbound;
891 __u32 upbound;
892 char dummy;
893 struct tipc_name_table_query query_info;
894
895 /* process (optional) depth argument */
896
897 if (!*args)
898 depth = 0;
899 else if (args[0] == 'a')
900 depth = 4;
901 else if (args[0] == 'p')
902 depth = 3;
903 else if (args[0] == 'n')
904 depth = 2;
905 else if (args[0] == 't')
906 depth = 1;
907 else
908 depth = 0;
909
910 if (depth > 0) {
911 args += strcspn(args, ",");
912 if (*args)
913 args++; /* skip over comma */
914 } else {
915 depth = 4;
916 }
917
918 /* process (optional) type arguments */
919
920 if (!*args) {
921 depth |= TIPC_NTQ_ALLTYPES;
922 type = lowbound = upbound = 0;
923 } else if (sscanf(args, "%u,%u,%u%c", &type, &lowbound, &upbound,
924 &dummy) == 3) {
925 /* do nothing more */
926 } else if (sscanf(args, "%u,%u%c", &type, &lowbound, &dummy) == 2) {
927 upbound = lowbound;
928 } else if (sscanf(args, "%u%c", &type, &dummy) == 1) {
929 lowbound = 0;
930 upbound = ~0;
931 } else
932 fatal(usage);
933
934 /* issue query & process response */
935
936 query_info.depth = htonl(depth);
937 query_info.type = htonl(type);
938 query_info.lowbound = htonl(lowbound);
939 query_info.upbound = htonl(upbound);
940
941 tlv_space = TLV_SET(tlv_area, TIPC_TLV_NAME_TBL_QUERY,
942 &query_info, sizeof(query_info));
943 tlv_space = do_command(TIPC_CMD_SHOW_NAME_TABLE, tlv_area, tlv_space,
944 tlv_area, sizeof(tlv_area));
945
946 if (!TLV_CHECK(tlv_area, tlv_space, TIPC_TLV_ULTRA_STRING))
947 fatal("corrupted reply message\n");
948
949 printf("%s", (char *)TLV_DATA(tlv_area));
950 }
951
get_media(char * dummy)952 static void get_media(char *dummy)
953 {
954 int tlv_space;
955 struct tlv_list_desc tlv_list;
956
957 tlv_space = do_command(TIPC_CMD_GET_MEDIA_NAMES, NULL, 0,
958 tlv_area, sizeof(tlv_area));
959
960 printf("Media%s:\n", for_dest());
961 if (!tlv_space) {
962 printf("No registered media\n");
963 return;
964 }
965
966 TLV_LIST_INIT(&tlv_list, tlv_area, tlv_space);
967 while (!TLV_LIST_EMPTY(&tlv_list)) {
968 if (!TLV_LIST_CHECK(&tlv_list, TIPC_TLV_MEDIA_NAME))
969 fatal("corrupted reply message\n");
970 printf("%s\n", (char *)TLV_LIST_DATA(&tlv_list));
971 TLV_LIST_STEP(&tlv_list);
972 }
973 }
974
975
976 /**
977 * do_these_bearers - perform operation on specified set of bearers
978 * @funcToRun: operation to be performed on bearer
979 * @str: bearer name pattern (if NULL, do operation on all bearers)
980 */
981
do_these_bearers(VOIDFUNCPTR funcToRun,const char * str)982 static void do_these_bearers(VOIDFUNCPTR funcToRun, const char *str)
983 {
984 int numBearers = 0;
985 int tlv_space;
986 struct tlv_list_desc tlv_list;
987 char *bname;
988
989 tlv_space = do_command(TIPC_CMD_GET_BEARER_NAMES, NULL, 0,
990 tlv_list_area, sizeof(tlv_list_area));
991
992 TLV_LIST_INIT(&tlv_list, tlv_list_area, tlv_space);
993
994 while (!TLV_LIST_EMPTY(&tlv_list)) {
995 if (!TLV_LIST_CHECK(&tlv_list, TIPC_TLV_BEARER_NAME))
996 fatal("corrupted reply message\n");
997 bname = (char *)TLV_LIST_DATA(&tlv_list);
998 if ((str == NULL) || (strstr(bname, str) != NULL)) {
999 funcToRun(bname);
1000 numBearers++;
1001 }
1002 TLV_LIST_STEP(&tlv_list);
1003 }
1004
1005 if (numBearers == 0) {
1006 if (str == NULL)
1007 printf("No active bearers\n");
1008 else
1009 printf("No bearers found matching pattern '%s'\n", str);
1010 }
1011 }
1012
get_bearer(char * bname)1013 static void get_bearer(char *bname)
1014 {
1015 printf("%s\n", bname);
1016 }
1017
get_bearerset(char * args)1018 static void get_bearerset(char *args)
1019 {
1020 printf("Bearers%s:\n", for_dest());
1021
1022 if (*args == 0)
1023 do_these_bearers(get_bearer, NULL); /* list all bearers */
1024 else if (args[0] == '?')
1025 do_these_bearers(get_bearer, args+1); /* list matching ones */
1026 else
1027 fatal("Invalid argument '%s' \n", args);
1028 }
1029
show_ports(char * dummy)1030 static void show_ports(char *dummy)
1031 {
1032 int tlv_space;
1033
1034 tlv_space = do_command(TIPC_CMD_SHOW_PORTS, NULL, 0,
1035 tlv_area, sizeof(tlv_area));
1036
1037 if (!TLV_CHECK(tlv_area, tlv_space, TIPC_TLV_ULTRA_STRING))
1038 fatal("corrupted reply message\n");
1039
1040 printf("Ports%s:\n%s", for_dest(), (char *)TLV_DATA(tlv_area));
1041 }
1042
1043 #if 0
1044 static void show_port_stats(char *args)
1045 {
1046 __u32 port_ref;
1047 __u32 port_ref_net;
1048 char dummy;
1049 int tlv_space;
1050
1051 if (sscanf(args, "%u%c", &port_ref, &dummy) != 1)
1052 fatal("invalid port reference\n");
1053
1054 port_ref_net = htonl(port_ref);
1055 tlv_space = TLV_SET(tlv_area, TIPC_TLV_PORT_REF,
1056 &port_ref_net, sizeof(port_ref_net));
1057 tlv_space = do_command(TIPC_CMD_SHOW_PORT_STATS, tlv_area, tlv_space,
1058 tlv_area, sizeof(tlv_area));
1059
1060 if (!TLV_CHECK(tlv_area, tlv_space, TIPC_TLV_ULTRA_STRING))
1061 fatal("corrupted reply message\n");
1062
1063 printf("%s", (char *)TLV_DATA(tlv_area));
1064 }
1065
1066 static void reset_port_stats(char *args)
1067 {
1068 __u32 port_ref;
1069 __u32 port_ref_net;
1070 char dummy;
1071 int tlv_space;
1072
1073 if (sscanf(args, "%u%c", &port_ref, &dummy) != 1)
1074 fatal("invalid port reference\n");
1075
1076 port_ref_net = htonl(port_ref);
1077 tlv_space = TLV_SET(tlv_area, TIPC_TLV_PORT_REF,
1078 &port_ref_net, sizeof(port_ref_net));
1079 tlv_space = do_command(TIPC_CMD_RESET_PORT_STATS, tlv_area, tlv_space,
1080 tlv_area, sizeof(tlv_area));
1081
1082 cprintf("Port %u statistics reset\n", port_ref);
1083 }
1084 #endif
1085
set_log_size(char * args)1086 static void set_log_size(char *args)
1087 {
1088 int tlv_space;
1089
1090 if (!*args) {
1091 tlv_space = do_command(TIPC_CMD_DUMP_LOG, NULL, 0,
1092 tlv_area, sizeof(tlv_area));
1093
1094 if (!TLV_CHECK(tlv_area, tlv_space, TIPC_TLV_ULTRA_STRING))
1095 fatal("corrupted reply message\n");
1096
1097 printf("Log dump%s:\n%s", for_dest(), (char *)TLV_DATA(tlv_area));
1098 } else {
1099 do_set_unsigned(args, TIPC_CMD_SET_LOG_SIZE, "log size",
1100 " (this will discard current log contents)");
1101 }
1102 }
1103
1104
set_link_value(char * linkName,__u32 dummy,const char * vname,int cmd,int val)1105 static void set_link_value(char *linkName, __u32 dummy, const char *vname,
1106 int cmd, int val)
1107 {
1108 struct tipc_link_config req_tlv;
1109 int tlv_space;
1110
1111 if (strcmp(linkName, "multicast-link") == 0)
1112 return;
1113
1114 req_tlv.value = htonl(val);
1115 strcpy(req_tlv.name, linkName);
1116 req_tlv.name[TIPC_MAX_LINK_NAME - 1] = '\0';
1117
1118 confirm("Change %s of link <%s>%s to %u? [Y/n]\n",
1119 vname, req_tlv.name, for_dest(), val);
1120
1121 tlv_space = TLV_SET(tlv_area, TIPC_TLV_LINK_CONFIG,
1122 &req_tlv, sizeof(req_tlv));
1123 tlv_space = do_command(cmd, tlv_area, tlv_space,
1124 tlv_area, sizeof(tlv_area));
1125
1126 cprintf("Link <%s>%s changed %s to %u\n",
1127 req_tlv.name, for_dest(), vname, val);
1128 }
1129
set_linkset_value(char * args,const char * vname,int cmd)1130 static void set_linkset_value(char *args, const char *vname, int cmd)
1131 {
1132 int val;
1133 char dummy;
1134 char *s = strchr(args, '/');
1135
1136 if (!s)
1137 fatal("Syntax: tipcConfig -l%c=<link-name>|<pattern>/<%s>\n",
1138 vname[0], vname);
1139
1140 *s++ = 0;
1141
1142 if (sscanf(s, "%u%c", &val, &dummy) != 1)
1143 fatal("non-numeric link %s specified\n", vname);
1144
1145 if (args[0] == '?')
1146 do_these_links(set_link_value, 0, args+1, vname, cmd, val);
1147 else
1148 set_link_value(args, 0, vname, cmd, val);
1149 }
1150
set_linkset_tolerance(char * args)1151 static void set_linkset_tolerance(char *args)
1152 {
1153 set_linkset_value(args, "tolerance", TIPC_CMD_SET_LINK_TOL);
1154 }
1155
set_linkset_priority(char * args)1156 static void set_linkset_priority(char *args)
1157 {
1158 set_linkset_value(args, "priority", TIPC_CMD_SET_LINK_PRI);
1159 }
1160
set_linkset_window(char * args)1161 static void set_linkset_window(char *args)
1162 {
1163 set_linkset_value(args, "window", TIPC_CMD_SET_LINK_WINDOW);
1164 }
1165
1166
enable_bearer(char * args)1167 static void enable_bearer(char *args)
1168 {
1169 struct tipc_bearer_config req_tlv;
1170 int tlv_space;
1171 char *a;
1172 char dummy;
1173
1174 while (args) {
1175 __u32 sc = dest & 0xfffff000; /* defaults to cluster scope */
1176 uint pri = TIPC_MEDIA_LINK_PRI; /* defaults to media priority */
1177 char *sc_str, *pri_str;
1178
1179 a = get_arg(&args);
1180 if ((sc_str = strchr(a, '/'))) {
1181 *sc_str++ = 0;
1182 if ((pri_str = strchr(sc_str, '/'))) {
1183 *pri_str++ = 0;
1184 if ((*pri_str != 0) &&
1185 sscanf(pri_str, "%u%c", &pri, &dummy) != 1)
1186 fatal("non-numeric bearer priority specified\n");
1187 }
1188 if (*sc_str != 0)
1189 sc = str2addr(sc_str);
1190 }
1191
1192 if (pri == TIPC_MEDIA_LINK_PRI)
1193 confirm("Enable bearer <%s>%s with detection scope %s and default media priority? [Y/n]",
1194 a, for_dest(), addr2str(sc));
1195 else
1196 confirm("Enable bearer <%s>%s with detection scope %s and priority %u? [Y/n]",
1197 a, for_dest(), addr2str(sc), pri);
1198
1199 req_tlv.priority = htonl(pri);
1200 req_tlv.detect_scope = htonl(sc);
1201 strncpy(req_tlv.name, a, TIPC_MAX_BEARER_NAME - 1);
1202 req_tlv.name[TIPC_MAX_BEARER_NAME - 1] = '\0';
1203
1204 tlv_space = TLV_SET(tlv_area, TIPC_TLV_BEARER_CONFIG,
1205 &req_tlv, sizeof(req_tlv));
1206 tlv_space = do_command(TIPC_CMD_ENABLE_BEARER, tlv_area, tlv_space,
1207 tlv_area, sizeof(tlv_area));
1208
1209 cprintf("Bearer <%s> enabled%s\n", a, for_dest());
1210 }
1211 }
1212
disable_bearer(char * bname)1213 static void disable_bearer(char *bname)
1214 {
1215 char bearer_name[TIPC_MAX_BEARER_NAME];
1216 int tlv_space;
1217
1218 strncpy(bearer_name, bname, TIPC_MAX_BEARER_NAME - 1);
1219 bearer_name[TIPC_MAX_BEARER_NAME - 1] = '\0';
1220
1221 confirm("Disable bearer <%s>%s ? [Y/n]", bearer_name, for_dest());
1222
1223 tlv_space = TLV_SET(tlv_area, TIPC_TLV_BEARER_NAME,
1224 bearer_name, sizeof(bearer_name));
1225 tlv_space = do_command(TIPC_CMD_DISABLE_BEARER, tlv_area, tlv_space,
1226 tlv_area, sizeof(tlv_area));
1227
1228 cprintf("Bearer <%s> disabled%s\n", bearer_name, for_dest());
1229 }
1230
disable_bearerset(char * args)1231 static void disable_bearerset(char *args)
1232 {
1233 if (args[0] == '?')
1234 do_these_bearers(disable_bearer, args+1); /* name pattern */
1235 else {
1236 while (args) {
1237 disable_bearer(get_arg(&args)); /* list of names */
1238 }
1239 }
1240 }
1241
1242
1243 #if 0
1244
1245 /* PROTOTYPE CODE FOR COMMANDS THAT AREN'T YET SUPPORTED */
1246
1247 const char *media_addr_string2(struct tipc_media_addr *a)
1248 {
1249 static char addr_area[128];
1250 uint addr_type = unpack_msg(a->type);
1251 unsigned char *addr = (unsigned char *) & a->dev_addr;
1252 uint i, len;
1253
1254 switch (addr_type) {
1255 case ETH_ADDR:
1256 {
1257 sprintf(addr_area,
1258 "ETH(%02x:%02x:%02x:%02x:%02x:%02x) ",
1259 addr[0], addr[1], addr[2], addr[3],
1260 addr[4], addr[5]);
1261 break;
1262 }
1263 case SOCKADDR_IPV4:
1264 {
1265 addr = (unsigned char *)&a->dev_addr.addr_in.sin_addr.s_addr;
1266 sprintf(addr_area, "SOCK_ADDR_IPV4(%u.%u.%u.%u:",
1267 addr[0], addr[1], addr[2], addr[3]);
1268 len = strlen(addr_area);
1269 sprintf(&addr_area[len], "%u)",
1270 a->dev_addr.addr_in.sin_port);
1271 break;
1272 }
1273 case SOCK_DESCR:
1274 {
1275 sprintf(addr_area, "SOCK_DESCR(%u)",
1276 ntohs(a->dev_addr.sock_descr));
1277 break;
1278 }
1279 default:
1280 {
1281 sprintf(addr_area, "UNKNOWN(%u):", addr_type);
1282 for (i = 0; i < (sizeof(*a) - sizeof(int)); i++) {
1283 sprintf(&addr_area[2 * i], "%02x ", addr[i]);
1284 }
1285 }
1286 }
1287 return addr_area;
1288 }
1289
1290 static void get_peer_address(char *args)
1291 {
1292 static struct tipc_cmd_result_msg *res_msg;
1293 static char addr_area[128];
1294 char link_name[TIPC_MAX_LINK_NAME];
1295 int i;
1296
1297 if (*args) {
1298 strncpy(link_name, args, TIPC_MAX_LINK_NAME - 1);
1299 link_name[TIPC_MAX_LINK_NAME-1] = '\0';
1300 } else
1301 fatal(usage);
1302 res_msg = do_safe_operation(TIPC_GET_PEER_ADDRESS,
1303 link_name, sizeof(link_name));
1304 if (res_msg) {
1305 printf("Peer Address of link <%s> is:\n", args);
1306 printf(" %s\n",
1307 media_addr_string2(&res_msg->result.peer_address));
1308 free(res_msg);
1309 } else {
1310 printf("Error getting peer address");
1311 }
1312 }
1313
1314 static void link_block(char *args)
1315 {
1316 static struct tipc_cmd_result_msg *res_msg;
1317 char link_name[TIPC_MAX_LINK_NAME];
1318
1319 strncpy(link_name, args, TIPC_MAX_LINK_NAME - 1);
1320 link_name[TIPC_MAX_LINK_NAME - 1] = '\0';
1321 confirm("Block link <%s> ? [Y/n]\n", link_name);
1322 res_msg = do_unsafe_operation(TIPC_CMD_BLOCK_LINK, link_name, sizeof(link_name));
1323 if (res_msg) {
1324 free(res_msg);
1325 cprintf("Link <%s> blocked\n", link_name);
1326 } else {
1327 printf("Error blocking link\n");
1328 }
1329 }
1330
1331 static void link_unblock(char *args)
1332 {
1333 static struct tipc_cmd_result_msg *res_msg;
1334 char link_name[TIPC_MAX_LINK_NAME];
1335
1336 strncpy(link_name, args, TIPC_MAX_LINK_NAME - 1);
1337 link_name[TIPC_MAX_LINK_NAME - 1] = '\0';
1338 confirm("Unblock link <%s> ? [Y/n]\n", link_name);
1339 res_msg = do_unsafe_operation(TIPC_CMD_UNBLOCK_LINK, link_name, sizeof(link_name));
1340 if (res_msg) {
1341 free(res_msg);
1342 cprintf("Link <%s> unblocked\n", link_name);
1343 } else {
1344 printf("Error unblocking link\n");
1345 }
1346 }
1347
1348 #define MASTER_NAME 2
1349 #define DIE 345644567
1350 #define MAX_NODES 512
1351
1352 static __u32 me = 0;
1353
1354 static __u32 zone_master_node(void)
1355 {
1356 struct tipc_subscr master_subscr = { {MASTER_NAME, 0, 0}, 0, 0,};
1357 struct tipc_event master_event;
1358 int topsd;
1359 struct sockaddr_tipc topsrv;
1360
1361 memset(&topsrv, 0, sizeof(topsrv));
1362 topsrv.addrtype = TIPC_ADDR_NAME;
1363 topsrv.addr.name.name.type = TIPC_TOP_SRV;
1364 topsrv.addr.name.name.instance = TIPC_TOP_SRV;
1365
1366 topsd = socket(AF_TIPC, SOCK_SEQPACKET, 0);
1367 if (topsd < 0) {
1368 perror("failed to create socket");
1369 exit(1);
1370 }
1371 if (connect(topsd, (struct sockaddr *) &topsrv, sizeof(topsrv)) < 0) {
1372 perror("failed to connect to topology server");
1373 close(topsd);
1374 exit(1);
1375 }
1376 if (send(topsd, &master_subscr, sizeof(master_subscr), 0) !=
1377 sizeof(master_subscr)) {
1378 perror("failed to send master subscription");
1379 close(topsd);
1380 exit(1);
1381 }
1382 if (recv(topsd, &master_event, sizeof(master_event), 0) !=
1383 sizeof(master_event)) {
1384 perror("failed to receive master subscription event");
1385 close(topsd);
1386 exit(1);
1387 }
1388 close(topsd);
1389 if (master_event.event != TIPC_PUBLISHED)
1390 return 0;
1391 return master_event.port.node;
1392 }
1393
1394 static void get_zone_master(char *optarg)
1395 {
1396 __u32 m = zone_master_node();
1397 if (m)
1398 printf("Zone Master is on %s\n", addr(m));
1399 else
1400 printf("No Zone Master Running\n");
1401 }
1402
1403 static void start_zone_master(char *optarg)
1404 {
1405 __u32 m = zone_master_node();
1406 if (m)
1407 fatal("Failed, Zone Master already on node %s\n",
1408 addr(m));
1409 if (!fork()) {
1410 struct sockaddr_tipc maddr;
1411 int sd = socket(AF_TIPC, SOCK_RDM, 0);
1412 if (sd < 0)
1413 fatal("Failed to create zone master socket\n");
1414 maddr.family = AF_TIPC;
1415 maddr.addrtype = TIPC_ADDR_NAMESEQ;
1416 maddr.addr.nameseq.type = MASTER_NAME;
1417 maddr.addr.nameseq.lower = 0;
1418 maddr.addr.nameseq.upper = ~0;
1419 maddr.scope = TIPC_ZONE_SCOPE;
1420 if (bind(sd, (struct sockaddr *) &maddr, sizeof(maddr)))
1421 fatal("Failed to bind to zone master name\n");
1422 zone_master_main(sd);
1423 }
1424 exit(EXIT_SUCCESS);
1425 }
1426
1427 static void kill_zone_master(char *optarg)
1428 {
1429 static struct tipc_cmd_result_msg *res_msg;
1430 if (zone_master_node() == me) {
1431 res_msg = do_operation_tipc(MASTER_NAME, me, DIE, me, 0, 0);
1432 free(res_msg);
1433 } else
1434 fatal("Must be Zone Master to do this\n");
1435 }
1436
1437 static void zone_master_main(int msd)
1438 {
1439 struct tipc_cmd_msg cmd_msg;
1440 static struct tipc_cmd_result_msg *res_msg;
1441 struct tipc_subscr net_subscr = { {0, 0, -1}, -1, 0, 0,};
1442 struct tipc_event net_event;
1443 int topsd;
1444 struct sockaddr_tipc topsrv;
1445 struct pollfd pfd[2];
1446 int i;
1447 struct tipc_cmd_result_msg *rmsg =
1448 (struct tipc_cmd_result_msg *) malloc(TIPC_MAX_USER_MSG_SIZE);
1449 struct {
1450 int sd;
1451 __u32 addr;
1452 } nodes[MAX_NODES];
1453
1454 memset(&nodes, 0, sizeof(nodes));
1455
1456 /*
1457 * Establish connection to topology server and subscribe for
1458 * network events
1459 */
1460 memset(&topsrv, 0, sizeof(topsrv));
1461 topsrv.addrtype = TIPC_ADDR_NAME;
1462 topsrv.addr.name.name.type = TIPC_TOP_SRV;
1463 topsrv.addr.name.name.instance = TIPC_TOP_SRV;
1464
1465 topsd = socket(AF_TIPC, SOCK_SEQPACKET, 0);
1466 if (topsd < 0) {
1467 perror("failed to create socket");
1468 exit(EXIT_FAILURE);
1469 }
1470 if (connect(topsd, (struct sockaddr *) &topsrv, sizeof(topsrv)) < 0) {
1471 perror("failed to connect to topology server");
1472 exit(EXIT_FAILURE);
1473 }
1474 if (send(topsd, &net_subscr, sizeof(net_subscr), 0) !=
1475 sizeof(net_subscr)) {
1476 perror("failed to send master subscription");
1477 exit(EXIT_FAILURE);
1478 }
1479 pfd[0].fd = topsd;
1480 pfd[0].events = 0xffff & ~POLLOUT;
1481
1482 cprintf("Zone Master daemeon started\n");
1483
1484 pfd[1].fd = msd;
1485 pfd[1].events = 0xffff & ~POLLOUT;
1486
1487 while (poll(pfd, 2, -1) > 0) {
1488 if (pfd[0].revents & POLLIN) {
1489 if (recv(topsd, &net_event, sizeof(net_event), 0)
1490 != sizeof(net_event)) {
1491 perror
1492 ("failed to receive network subscription event");
1493 exit(EXIT_FAILURE);
1494 }
1495 if (net_event.event == TIPC_PUBLISHED) {
1496 for (i = 0; nodes[i].sd; i++);
1497 nodes[i].addr = net_event.found_lower;
1498 nodes[i].sd =
1499 socket(AF_TIPC, SOCK_SEQPACKET, 0);
1500 if (nodes[i].sd < 0)
1501 err(1,
1502 "Failed to create socket \n");
1503 res_msg = do_operation_tipc(0, nodes[i].addr,
1504 TIPC_ESTABLISH, nodes[i].addr,
1505 nodes[i].sd, 0, 0);
1506 free(res_msg);
1507 cprintf("Zone Master connected to %s\n",
1508 addr(nodes[i].addr));
1509 }
1510 }
1511 if (pfd[1].revents & POLLIN) {
1512 struct sockaddr_tipc tipc_orig, tipc_dest;
1513 socklen_t origlen = sizeof(tipc_orig);
1514 int sz =
1515 recvfrom(msd, &cmd_msg, sizeof(cmd_msg), 0,
1516 (struct sockaddr *) &tipc_orig, &origlen);
1517
1518 if (tipc_orig.addr.id.node != me)
1519 continue;
1520
1521 /****
1522 * MUST BE REPLACED BY SOMETHING ELSE
1523 *
1524 ioctl(msd,TIPC_GET_DEST_ADDR,&tipc_dest);
1525 */
1526 if ((pfd[1].revents & POLLERR) == 0) {
1527 uint dnode = 0x1001001; //tipc_dest.addr.name.name.instance;
1528 uint rsz = sizeof(*rmsg);
1529 rmsg->retval = -EINVAL;
1530 if (unpack_msg(cmd_msg.cmd) == DIE) {
1531 rmsg->retval = TIPC_OK;
1532 sendto(msd, rmsg, sizeof(*rmsg), 0,
1533 (struct sockaddr *) &tipc_orig,
1534 sizeof(tipc_orig));
1535 cprintf
1536 ("Zone Master terminating...\n");
1537 exit(EXIT_SUCCESS);
1538 }
1539 for (i = 0;
1540 (nodes[i].addr != dnode)
1541 && (i < MAX_NODES); i++);
1542 if (i < MAX_NODES) {
1543 if ((send(nodes[i].sd, &cmd_msg,
1544 sizeof(cmd_msg), 0) <= 0)
1545 || ((rsz = recv(nodes[i].sd, rmsg,
1546 TIPC_MAX_USER_MSG_SIZE,
1547 0)) <= 0)) {
1548 close(nodes[i].sd);
1549 nodes[i].sd = nodes[i].addr = 0;
1550 }
1551 }
1552 sendto(msd, rmsg, rsz, 0,
1553 (struct sockaddr *) &tipc_orig, sizeof(tipc_orig));
1554 }
1555 }
1556 }
1557 }
1558
1559 #endif
1560
1561
1562 /******************************************************************************
1563 *
1564 * Basic data structures and routines associated with command option processing
1565 *
1566 */
1567
1568 #define OPT_BASE '@'
1569
1570 struct command {
1571 void (*fcn) (char *args);
1572 char args[128];
1573 };
1574
1575 static char usage[] =
1576 "Usage: \n"
1577 " tipc-config option [option ...]\n"
1578 " \n"
1579 " valid options:\n"
1580 " -v Verbose output\n"
1581 " -i Interactive set operations\n"
1582 " -dest =<addr> Command destination node\n"
1583 " -addr [=<addr>] Get/set node address\n"
1584 " -netid[=<value>] Get/set network id\n"
1585 " -mng [=enable|disable] Get/set remote management\n"
1586 " -nt [=[<depth>,]<type>[,<low>[,<up>]]] Get name table\n"
1587 " where <depth> = types|names|ports|all\n"
1588 #if 1
1589 " -p Get port info\n"
1590 #else
1591 " -p [=all|bound|connected|<port>] Get port info\n"
1592 " -ps =<port> Get port statistics\n"
1593 " -psr =<port> Reset port statistics\n"
1594 #endif
1595 " -m Get media\n"
1596 " -b [=<pattern>] Get bearers\n"
1597 " -be =<bname>[/<scope>[/<priority>]]] Enable bearer\n"
1598 " -bd =<bname>|<pattern> Disable bearer\n"
1599 " -n [=<addr>] Get nodes in domain\n"
1600 " -l [=<addr>|<pattern>] Get links for domain\n"
1601 " -ls [=<linkname>|<pattern>] Get link statistics\n"
1602 " -lsr =<linkname>|<pattern> Reset link statistics\n"
1603 " -lp =<linkname>|<pattern>/<value> Set link priority\n"
1604 " -lt =<linkname>|<pattern>/<value> Set link tolerance\n"
1605 " -lw =<linkname>|<pattern>/<value> Set link window\n"
1606 " -max_ports | -max_publ | -max_subscr | Get/set max number of ports,\n"
1607 " -max_zones | -max_clusters | -max_nodes | publications, etc.\n"
1608 " -max_slaves [=<value>] \n"
1609 " -log [=<size>] Dump/resize log\n"
1610 " -V Program version\n"
1611 " -help This usage list\n"
1612 #if 0
1613 " -r =<addr> Get routes to domain\n"
1614 " -lc =<addr>,bearer=<bname>, Create link\n"
1615 " ip=<ip.ad.dr.ess:port>| \n"
1616 " eth=<et:he:ra:dd:re:ss> \n"
1617 " -ld =<linkname> Delete link \n"
1618 " -lb =<linkname> Block link \n"
1619 " -lu =<linkname> Unblock link\n"
1620 " -la =<linkname> Get link peer address\n"
1621 " -zm Get zone master\n"
1622 " [=enable|disable ] Assume/relinquish zone\n"
1623 #endif
1624 ; /* end of concatenated string literal */
1625
1626 /*
1627 * Option structure field usage in tipc-config application:
1628 * 1) option name
1629 * 2) argument count
1630 * 0 if argument is not allowed
1631 * 1 if argument is required
1632 * 2 if argument is optional
1633 * 3) always set to 0
1634 * 4) value to return
1635 */
1636
1637 static struct option options[] = {
1638 {"help", 0, 0, '0'},
1639 {"v", 0, 0, '1'},
1640 {"i", 0, 0, '2'},
1641 {"dest", 1, 0, '3'},
1642 {"V", 0, 0, '4'},
1643 {"addr", 2, 0, OPT_BASE + 0},
1644 {"netid", 2, 0, OPT_BASE + 1},
1645 {"mng", 2, 0, OPT_BASE + 2},
1646 {"nt", 2, 0, OPT_BASE + 3},
1647 {"p", 0, 0, OPT_BASE + 4},
1648 #if 0
1649 {"ps", 1, 0, OPT_BASE + 5},
1650 {"psr", 1, 0, OPT_BASE + 6},
1651 #endif
1652 {"m", 0, 0, OPT_BASE + 7},
1653 {"b", 2, 0, OPT_BASE + 8},
1654 {"be", 1, 0, OPT_BASE + 9},
1655 {"bd", 1, 0, OPT_BASE + 10},
1656 {"n", 2, 0, OPT_BASE + 11},
1657 #if 0
1658 {"r", 1, 0, OPT_BASE + 12},
1659 #endif
1660 {"l", 2, 0, OPT_BASE + 13},
1661 {"ls", 2, 0, OPT_BASE + 14},
1662 {"lsr", 1, 0, OPT_BASE + 15},
1663 #if 0
1664 {"lc", 2, 0, OPT_BASE + 16},
1665 {"ld", 2, 0, OPT_BASE + 17},
1666 {"lb", 2, 0, OPT_BASE + 18},
1667 {"lu", 2, 0, OPT_BASE + 19},
1668 #endif
1669 {"lp", 1, 0, OPT_BASE + 20},
1670 {"lw", 1, 0, OPT_BASE + 21},
1671 {"lt", 1, 0, OPT_BASE + 22},
1672 #if 0
1673 {"la", 2, 0, OPT_BASE + 23},
1674 {"zm", 2, 0, OPT_BASE + 24},
1675 #endif
1676 {"max_ports", 2, 0, OPT_BASE + 25},
1677 {"max_subscr", 2, 0, OPT_BASE + 26},
1678 {"max_publ", 2, 0, OPT_BASE + 27},
1679 {"max_zones", 2, 0, OPT_BASE + 28},
1680 {"max_clusters", 2, 0, OPT_BASE + 29},
1681 {"max_nodes", 2, 0, OPT_BASE + 30},
1682 {"max_slaves", 2, 0, OPT_BASE + 31},
1683 {"log", 2, 0, OPT_BASE + 32},
1684 {0, 0, 0, 0}
1685 };
1686
1687 void (*cmd_array[])(char *args) = {
1688 set_node_addr,
1689 set_netid,
1690 set_remote_mng,
1691 show_name_table,
1692 show_ports,
1693 NULL, /* show_port_stats, */
1694 NULL, /* reset_port_stats, */
1695 get_media,
1696 get_bearerset,
1697 enable_bearer,
1698 disable_bearerset,
1699 get_nodes,
1700 NULL, /* get routes */
1701 get_linkset,
1702 show_linkset_stats,
1703 reset_linkset_stats,
1704 NULL, /* create link */
1705 NULL, /* delete link */
1706 NULL, /* link_block */
1707 NULL, /* link_unblock */
1708 set_linkset_priority,
1709 set_linkset_window,
1710 set_linkset_tolerance,
1711 NULL, /* get_peer_address */
1712 NULL, /* zone master */
1713 set_max_ports,
1714 set_max_subscr,
1715 set_max_publ,
1716 set_max_zones,
1717 set_max_clusters,
1718 set_max_nodes,
1719 set_max_slaves,
1720 set_log_size,
1721 NULL
1722 };
1723
1724 /*
1725 * Mainline parses option list and processes each option. Most options are
1726 * not actually executed until parsing is complete in case they are impacted
1727 * by options that appear later in the list.
1728 */
1729
main(int argc,char * argv[],char * dummy[])1730 int main(int argc, char *argv[], char *dummy[])
1731 {
1732 struct command commands[MAX_COMMANDS];
1733 int cno, cno2;
1734 int c;
1735
1736 if (argc == 1)
1737 fatal(usage);
1738
1739 dest = own_node();
1740
1741 cno = 0;
1742 while ((c = getopt_long_only(argc, argv, "", options, NULL)) != EOF) {
1743
1744 if (c >= OPT_BASE) {
1745 if (cno >= MAX_COMMANDS)
1746 fatal("too many options specified\n");
1747
1748 commands[cno].fcn = cmd_array[c - OPT_BASE];
1749 if (optarg)
1750 strcpy(commands[cno].args, optarg);
1751 else
1752 commands[cno].args[0] = '\0';
1753 cno++;
1754 } else {
1755 switch (c) {
1756 case '0':
1757 fatal(usage);
1758 break;
1759 case '1':
1760 verbose = 1;
1761 break;
1762 case '2':
1763 interactive = 1;
1764 break;
1765 case '3':
1766 dest = str2addr(optarg);
1767 break;
1768 case '4':
1769 printf("TIPC configuration tool version "
1770 VERSION "\n");
1771 break;
1772 default:
1773 /* getopt_long_only() generates the error msg */
1774 exit(EXIT_FAILURE);
1775 break;
1776 }
1777 }
1778
1779 }
1780
1781 if (optind < argc) {
1782 /* detects arguments that don't start with a '-' sign */
1783 fatal("unexpected command argument '%s'\n", argv[optind]);
1784 }
1785
1786 for (cno2 = 0; cno2 < cno; cno2++) {
1787 if (!commands[cno2].fcn)
1788 fatal("command table error\n");
1789 commands[cno2].fcn(commands[cno2].args);
1790 }
1791
1792 return 0;
1793 }
1794