• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * ctrl.c	generic netlink controller
3   *
4   *		This program is free software; you can distribute it and/or
5   *		modify it under the terms of the GNU General Public License
6   *		as published by the Free Software Foundation; either version
7   *		2 of the License, or (at your option) any later version.
8   *
9   * Authors:	J Hadi Salim (hadi@cyberus.ca)
10   *		Johannes Berg (johannes@sipsolutions.net)
11   */
12  
13  #include <stdio.h>
14  #include <stdlib.h>
15  #include <unistd.h>
16  #include <syslog.h>
17  #include <fcntl.h>
18  #include <sys/socket.h>
19  #include <netinet/in.h>
20  #include <arpa/inet.h>
21  #include <string.h>
22  
23  #include "utils.h"
24  #include "genl_utils.h"
25  
26  #define GENL_MAX_FAM_OPS	256
27  #define GENL_MAX_FAM_GRPS	256
28  
usage(void)29  static int usage(void)
30  {
31  	fprintf(stderr,"Usage: ctrl <CMD>\n" \
32  		       "CMD   := get <PARMS> | list | monitor\n" \
33  		       "PARMS := name <name> | id <id>\n" \
34  		       "Examples:\n" \
35  		       "\tctrl ls\n" \
36  		       "\tctrl monitor\n" \
37  		       "\tctrl get name foobar\n" \
38  		       "\tctrl get id 0xF\n");
39  	return -1;
40  }
41  
genl_ctrl_resolve_family(const char * family)42  int genl_ctrl_resolve_family(const char *family)
43  {
44  	struct rtnl_handle rth;
45  	struct nlmsghdr *nlh;
46  	struct genlmsghdr *ghdr;
47  	int ret = 0;
48  	struct {
49  		struct nlmsghdr         n;
50  		char                    buf[4096];
51  	} req;
52  
53  	memset(&req, 0, sizeof(req));
54  
55  	nlh = &req.n;
56  	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
57  	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
58  	nlh->nlmsg_type = GENL_ID_CTRL;
59  
60  	ghdr = NLMSG_DATA(&req.n);
61  	ghdr->cmd = CTRL_CMD_GETFAMILY;
62  
63  	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
64  		fprintf(stderr, "Cannot open generic netlink socket\n");
65  		exit(1);
66  	}
67  
68  	addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
69  
70  	if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) {
71  		fprintf(stderr, "Error talking to the kernel\n");
72  		goto errout;
73  	}
74  
75  	{
76  		struct rtattr *tb[CTRL_ATTR_MAX + 1];
77  		struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
78  		int len = nlh->nlmsg_len;
79  		struct rtattr *attrs;
80  
81  		if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
82  			fprintf(stderr, "Not a controller message, nlmsg_len=%d "
83  				"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
84  			goto errout;
85  		}
86  
87  		if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
88  			fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
89  			goto errout;
90  		}
91  
92  		len -= NLMSG_LENGTH(GENL_HDRLEN);
93  
94  		if (len < 0) {
95  			fprintf(stderr, "wrong controller message len %d\n", len);
96  			return -1;
97  		}
98  
99  		attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
100  		parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
101  
102  		if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
103  			fprintf(stderr, "Missing family id TLV\n");
104  			goto errout;
105  		}
106  
107  		ret = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
108  	}
109  
110  errout:
111  	rtnl_close(&rth);
112  	return ret;
113  }
114  
print_ctrl_cmd_flags(FILE * fp,__u32 fl)115  void print_ctrl_cmd_flags(FILE *fp, __u32 fl)
116  {
117  	fprintf(fp, "\n\t\tCapabilities (0x%x):\n ", fl);
118  	if (!fl) {
119  		fprintf(fp, "\n");
120  		return;
121  	}
122  	fprintf(fp, "\t\t ");
123  
124  	if (fl & GENL_ADMIN_PERM)
125  		fprintf(fp, " requires admin permission;");
126  	if (fl & GENL_CMD_CAP_DO)
127  		fprintf(fp, " can doit;");
128  	if (fl & GENL_CMD_CAP_DUMP)
129  		fprintf(fp, " can dumpit;");
130  	if (fl & GENL_CMD_CAP_HASPOL)
131  		fprintf(fp, " has policy");
132  
133  	fprintf(fp, "\n");
134  }
135  
print_ctrl_cmds(FILE * fp,struct rtattr * arg,__u32 ctrl_ver)136  static int print_ctrl_cmds(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
137  {
138  	struct rtattr *tb[CTRL_ATTR_OP_MAX + 1];
139  
140  	if (arg == NULL)
141  		return -1;
142  
143  	parse_rtattr_nested(tb, CTRL_ATTR_OP_MAX, arg);
144  	if (tb[CTRL_ATTR_OP_ID]) {
145  		__u32 *id = RTA_DATA(tb[CTRL_ATTR_OP_ID]);
146  		fprintf(fp, " ID-0x%x ",*id);
147  	}
148  	/* we are only gonna do this for newer version of the controller */
149  	if (tb[CTRL_ATTR_OP_FLAGS] && ctrl_ver >= 0x2) {
150  		__u32 *fl = RTA_DATA(tb[CTRL_ATTR_OP_FLAGS]);
151  		print_ctrl_cmd_flags(fp, *fl);
152  	}
153  	return 0;
154  
155  }
156  
print_ctrl_grp(FILE * fp,struct rtattr * arg,__u32 ctrl_ver)157  static int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
158  {
159  	struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
160  
161  	if (arg == NULL)
162  		return -1;
163  
164  	parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
165  	if (tb[2]) {
166  		__u32 *id = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]);
167  		fprintf(fp, " ID-0x%x ",*id);
168  	}
169  	if (tb[1]) {
170  		char *name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
171  		fprintf(fp, " name: %s ", name);
172  	}
173  	return 0;
174  
175  }
176  
177  /*
178   * The controller sends one nlmsg per family
179  */
print_ctrl(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)180  static int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
181  		      void *arg)
182  {
183  	struct rtattr *tb[CTRL_ATTR_MAX + 1];
184  	struct genlmsghdr *ghdr = NLMSG_DATA(n);
185  	int len = n->nlmsg_len;
186  	struct rtattr *attrs;
187  	FILE *fp = (FILE *) arg;
188  	__u32 ctrl_v = 0x1;
189  
190  	if (n->nlmsg_type !=  GENL_ID_CTRL) {
191  		fprintf(stderr, "Not a controller message, nlmsg_len=%d "
192  			"nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type);
193  		return 0;
194  	}
195  
196  	if (ghdr->cmd != CTRL_CMD_GETFAMILY &&
197  	    ghdr->cmd != CTRL_CMD_DELFAMILY &&
198  	    ghdr->cmd != CTRL_CMD_NEWFAMILY &&
199  	    ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
200  	    ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
201  		fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
202  		return 0;
203  	}
204  
205  	len -= NLMSG_LENGTH(GENL_HDRLEN);
206  
207  	if (len < 0) {
208  		fprintf(stderr, "wrong controller message len %d\n", len);
209  		return -1;
210  	}
211  
212  	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
213  	parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
214  
215  	if (tb[CTRL_ATTR_FAMILY_NAME]) {
216  		char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
217  		fprintf(fp, "\nName: %s\n",name);
218  	}
219  	if (tb[CTRL_ATTR_FAMILY_ID]) {
220  		__u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
221  		fprintf(fp, "\tID: 0x%x ",*id);
222  	}
223  	if (tb[CTRL_ATTR_VERSION]) {
224  		__u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]);
225  		fprintf(fp, " Version: 0x%x ",*v);
226  		ctrl_v = *v;
227  	}
228  	if (tb[CTRL_ATTR_HDRSIZE]) {
229  		__u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]);
230  		fprintf(fp, " header size: %d ",*h);
231  	}
232  	if (tb[CTRL_ATTR_MAXATTR]) {
233  		__u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
234  		fprintf(fp, " max attribs: %d ",*ma);
235  	}
236  	/* end of family definitions .. */
237  	fprintf(fp,"\n");
238  	if (tb[CTRL_ATTR_OPS]) {
239  		struct rtattr *tb2[GENL_MAX_FAM_OPS];
240  		int i=0;
241  		parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]);
242  		fprintf(fp, "\tcommands supported: \n");
243  		for (i = 0; i < GENL_MAX_FAM_OPS; i++) {
244  			if (tb2[i]) {
245  				fprintf(fp, "\t\t#%d: ", i);
246  				if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) {
247  					fprintf(fp, "Error printing command\n");
248  				}
249  				/* for next command */
250  				fprintf(fp,"\n");
251  			}
252  		}
253  
254  		/* end of family::cmds definitions .. */
255  		fprintf(fp,"\n");
256  	}
257  
258  	if (tb[CTRL_ATTR_MCAST_GROUPS]) {
259  		struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
260  		int i;
261  
262  		parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
263  				    tb[CTRL_ATTR_MCAST_GROUPS]);
264  		fprintf(fp, "\tmulticast groups:\n");
265  
266  		for (i = 0; i < GENL_MAX_FAM_GRPS; i++) {
267  			if (tb2[i]) {
268  				fprintf(fp, "\t\t#%d: ", i);
269  				if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v))
270  					fprintf(fp, "Error printing group\n");
271  				/* for next group */
272  				fprintf(fp,"\n");
273  			}
274  		}
275  
276  		/* end of family::groups definitions .. */
277  		fprintf(fp,"\n");
278  	}
279  
280  	fflush(fp);
281  	return 0;
282  }
283  
ctrl_list(int cmd,int argc,char ** argv)284  static int ctrl_list(int cmd, int argc, char **argv)
285  {
286  	struct rtnl_handle rth;
287  	struct nlmsghdr *nlh;
288  	struct genlmsghdr *ghdr;
289  	int ret = -1;
290  	char d[GENL_NAMSIZ];
291  	struct {
292  		struct nlmsghdr         n;
293  		char                    buf[4096];
294  	} req;
295  
296  	memset(&req, 0, sizeof(req));
297  
298  	nlh = &req.n;
299  	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
300  	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
301  	nlh->nlmsg_type = GENL_ID_CTRL;
302  
303  	ghdr = NLMSG_DATA(&req.n);
304  	ghdr->cmd = CTRL_CMD_GETFAMILY;
305  
306  	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
307  		fprintf(stderr, "Cannot open generic netlink socket\n");
308  		exit(1);
309  	}
310  
311  	if (cmd == CTRL_CMD_GETFAMILY) {
312  		if (argc != 2) {
313  			fprintf(stderr, "Wrong number of params\n");
314  			return -1;
315  		}
316  
317  		if (matches(*argv, "name") == 0) {
318  			NEXT_ARG();
319  			strncpy(d, *argv, sizeof (d) - 1);
320  			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
321  				  d, strlen(d) + 1);
322  		} else if (matches(*argv, "id") == 0) {
323  			__u16 id;
324  			NEXT_ARG();
325  			if (get_u16(&id, *argv, 0)) {
326  				fprintf(stderr, "Illegal \"id\"\n");
327  				goto ctrl_done;
328  			}
329  
330  			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2);
331  
332  		} else {
333  			fprintf(stderr, "Wrong params\n");
334  			goto ctrl_done;
335  		}
336  
337  		if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) {
338  			fprintf(stderr, "Error talking to the kernel\n");
339  			goto ctrl_done;
340  		}
341  
342  		if (print_ctrl(NULL, nlh, (void *) stdout) < 0) {
343  			fprintf(stderr, "Dump terminated\n");
344  			goto ctrl_done;
345  		}
346  
347  	}
348  
349  	if (cmd == CTRL_CMD_UNSPEC) {
350  		nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
351  		nlh->nlmsg_seq = rth.dump = ++rth.seq;
352  
353  		if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) {
354  			perror("Failed to send dump request\n");
355  			goto ctrl_done;
356  		}
357  
358  		rtnl_dump_filter(&rth, print_ctrl, stdout);
359  
360          }
361  
362  	ret = 0;
363  ctrl_done:
364  	rtnl_close(&rth);
365  	return ret;
366  }
367  
ctrl_listen(int argc,char ** argv)368  static int ctrl_listen(int argc, char **argv)
369  {
370  	struct rtnl_handle rth;
371  
372  	if (rtnl_open_byproto(&rth, nl_mgrp(GENL_ID_CTRL), NETLINK_GENERIC) < 0) {
373  		fprintf(stderr, "Canot open generic netlink socket\n");
374  		return -1;
375  	}
376  
377  	if (rtnl_listen(&rth, print_ctrl, (void *) stdout) < 0)
378  		return -1;
379  
380  	return 0;
381  }
382  
parse_ctrl(struct genl_util * a,int argc,char ** argv)383  static int parse_ctrl(struct genl_util *a, int argc, char **argv)
384  {
385  	argv++;
386  	if (--argc <= 0) {
387  		fprintf(stderr, "wrong controller params\n");
388  		return -1;
389  	}
390  
391  	if (matches(*argv, "monitor") == 0)
392  		return ctrl_listen(argc-1, argv+1);
393  	if (matches(*argv, "get") == 0)
394  		return ctrl_list(CTRL_CMD_GETFAMILY, argc-1, argv+1);
395  	if (matches(*argv, "list") == 0 ||
396  	    matches(*argv, "show") == 0 ||
397  	    matches(*argv, "lst") == 0)
398  		return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1);
399  	if (matches(*argv, "help") == 0)
400  		return usage();
401  
402  	fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl -help\".\n",
403  		*argv);
404  
405  	return -1;
406  }
407  
408  struct genl_util ctrl_genl_util = {
409  	.name = "ctrl",
410  	.parse_genlopt = parse_ctrl,
411  	.print_genlopt = print_ctrl,
412  };
413