]> rtime.felk.cvut.cz Git - lisovros/iproute2_canprio.git/blob - genl/ctrl.c
30ea4d704df43f851c2d0682a9af2f4886b6e6a0
[lisovros/iproute2_canprio.git] / genl / ctrl.c
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
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
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, NULL, NULL) < 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 = *(__u16 *) RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
108         }
109
110 errout:
111         rtnl_close(&rth);
112         return ret;
113 }
114
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         
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
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 */
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
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, NULL, NULL) < 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, (const char *) 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, NULL, NULL);
359
360         }
361
362         ret = 0;
363 ctrl_done:
364         rtnl_close(&rth);
365         return ret;
366 }
367
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
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 };