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