165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim/*
265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim * ctrl.c	generic netlink controller
365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim *
465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim *		This program is free software; you can distribute it and/or
565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim *		modify it under the terms of the GNU General Public License
665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim *		as published by the Free Software Foundation; either version
765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim *		2 of the License, or (at your option) any later version.
865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim *
980c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg * Authors:	J Hadi Salim (hadi@cyberus.ca)
1080c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg *		Johannes Berg (johannes@sipsolutions.net)
1165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim */
1265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
1365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <stdio.h>
1465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <stdlib.h>
1565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <unistd.h>
1665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <syslog.h>
1765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <fcntl.h>
1865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <sys/socket.h>
1965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <netinet/in.h>
2065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <arpa/inet.h>
2165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include <string.h>
2265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
2365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include "utils.h"
2465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim#include "genl_utils.h"
2565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
2626328fc3933f377c47fb8b06feabbde5e12ed650jamal#define GENL_MAX_FAM_OPS	256
2780c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg#define GENL_MAX_FAM_GRPS	256
2880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
2965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimstatic int usage(void)
3065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim{
3165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	fprintf(stderr,"Usage: ctrl <CMD>\n" \
3265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		       "CMD   := get <PARMS> | list | monitor\n" \
3365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		       "PARMS := name <name> | id <id>\n" \
3465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		       "Examples:\n" \
3565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		       "\tctrl ls\n" \
3665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		       "\tctrl monitor\n" \
3765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		       "\tctrl get name foobar\n" \
3865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		       "\tctrl get id 0xF\n");
3965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	return -1;
4065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim}
4165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
4265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimint genl_ctrl_resolve_family(const char *family)
4365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim{
4465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct rtnl_handle rth;
4565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct nlmsghdr *nlh;
4665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct genlmsghdr *ghdr;
4765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	int ret = 0;
4865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct {
4965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		struct nlmsghdr         n;
5065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		char                    buf[4096];
5165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	} req;
5265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
5365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	memset(&req, 0, sizeof(req));
5465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
5565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh = &req.n;
5665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
5765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
5865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh->nlmsg_type = GENL_ID_CTRL;
5965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
6065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	ghdr = NLMSG_DATA(&req.n);
6165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	ghdr->cmd = CTRL_CMD_GETFAMILY;
6265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
6365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
6465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		fprintf(stderr, "Cannot open generic netlink socket\n");
6565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		exit(1);
6665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
6765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
6865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);
6965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
70cd70f3f522e04b4d2fa80ae10292379bf223a53bStephen Hemminger	if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) {
7165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		fprintf(stderr, "Error talking to the kernel\n");
7265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		goto errout;
7365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
7465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
7565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	{
7665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		struct rtattr *tb[CTRL_ATTR_MAX + 1];
7765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
7865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		int len = nlh->nlmsg_len;
7965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		struct rtattr *attrs;
8065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
8165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
8265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			fprintf(stderr, "Not a controller message, nlmsg_len=%d "
8365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim				"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
8465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			goto errout;
8565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
8665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
8765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
8880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg			fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
8965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			goto errout;
9065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
9165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
9265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		len -= NLMSG_LENGTH(GENL_HDRLEN);
9365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
9465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		if (len < 0) {
9565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			fprintf(stderr, "wrong controller message len %d\n", len);
9665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			return -1;
9765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
9865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
9965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
10065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
10165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
10265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
10365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			fprintf(stderr, "Missing family id TLV\n");
10465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			goto errout;
10565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
10665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
107ff24746cca1ef0c92d46614158e6672acd6b63d3Stephen Hemminger		ret = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
10865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
10965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
11065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimerrout:
11165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	rtnl_close(&rth);
11265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	return ret;
11365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim}
11465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
11526328fc3933f377c47fb8b06feabbde5e12ed650jamalvoid print_ctrl_cmd_flags(FILE *fp, __u32 fl)
11626328fc3933f377c47fb8b06feabbde5e12ed650jamal{
11726328fc3933f377c47fb8b06feabbde5e12ed650jamal	fprintf(fp, "\n\t\tCapabilities (0x%x):\n ", fl);
11826328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (!fl) {
11926328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, "\n");
12026328fc3933f377c47fb8b06feabbde5e12ed650jamal		return;
12126328fc3933f377c47fb8b06feabbde5e12ed650jamal	}
12226328fc3933f377c47fb8b06feabbde5e12ed650jamal	fprintf(fp, "\t\t ");
12326328fc3933f377c47fb8b06feabbde5e12ed650jamal
12426328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (fl & GENL_ADMIN_PERM)
12526328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " requires admin permission;");
12626328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (fl & GENL_CMD_CAP_DO)
12726328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " can doit;");
12826328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (fl & GENL_CMD_CAP_DUMP)
12926328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " can dumpit;");
13026328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (fl & GENL_CMD_CAP_HASPOL)
13126328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " has policy");
13226328fc3933f377c47fb8b06feabbde5e12ed650jamal
13326328fc3933f377c47fb8b06feabbde5e12ed650jamal	fprintf(fp, "\n");
13426328fc3933f377c47fb8b06feabbde5e12ed650jamal}
13526328fc3933f377c47fb8b06feabbde5e12ed650jamal
13626328fc3933f377c47fb8b06feabbde5e12ed650jamalstatic int print_ctrl_cmds(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
13726328fc3933f377c47fb8b06feabbde5e12ed650jamal{
13826328fc3933f377c47fb8b06feabbde5e12ed650jamal	struct rtattr *tb[CTRL_ATTR_OP_MAX + 1];
13926328fc3933f377c47fb8b06feabbde5e12ed650jamal
14026328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (arg == NULL)
14126328fc3933f377c47fb8b06feabbde5e12ed650jamal		return -1;
14226328fc3933f377c47fb8b06feabbde5e12ed650jamal
14326328fc3933f377c47fb8b06feabbde5e12ed650jamal	parse_rtattr_nested(tb, CTRL_ATTR_OP_MAX, arg);
14426328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (tb[CTRL_ATTR_OP_ID]) {
14526328fc3933f377c47fb8b06feabbde5e12ed650jamal		__u32 *id = RTA_DATA(tb[CTRL_ATTR_OP_ID]);
14626328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " ID-0x%x ",*id);
14726328fc3933f377c47fb8b06feabbde5e12ed650jamal	}
14826328fc3933f377c47fb8b06feabbde5e12ed650jamal	/* we are only gonna do this for newer version of the controller */
14926328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (tb[CTRL_ATTR_OP_FLAGS] && ctrl_ver >= 0x2) {
15026328fc3933f377c47fb8b06feabbde5e12ed650jamal		__u32 *fl = RTA_DATA(tb[CTRL_ATTR_OP_FLAGS]);
15126328fc3933f377c47fb8b06feabbde5e12ed650jamal		print_ctrl_cmd_flags(fp, *fl);
15226328fc3933f377c47fb8b06feabbde5e12ed650jamal	}
15326328fc3933f377c47fb8b06feabbde5e12ed650jamal	return 0;
15426328fc3933f377c47fb8b06feabbde5e12ed650jamal
15526328fc3933f377c47fb8b06feabbde5e12ed650jamal}
15626328fc3933f377c47fb8b06feabbde5e12ed650jamal
15780c05b0976be86308e92b2837e0a94c484e388b4Johannes Bergstatic int print_ctrl_grp(FILE *fp, struct rtattr *arg, __u32 ctrl_ver)
15880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg{
15980c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	struct rtattr *tb[CTRL_ATTR_MCAST_GRP_MAX + 1];
16080c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
16180c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	if (arg == NULL)
16280c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		return -1;
16380c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
16480c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	parse_rtattr_nested(tb, CTRL_ATTR_MCAST_GRP_MAX, arg);
16580c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	if (tb[2]) {
16680c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		__u32 *id = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_ID]);
16780c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		fprintf(fp, " ID-0x%x ",*id);
16880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	}
16980c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	if (tb[1]) {
17080c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		char *name = RTA_DATA(tb[CTRL_ATTR_MCAST_GRP_NAME]);
17180c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		fprintf(fp, " name: %s ", name);
17280c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	}
17380c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	return 0;
17480c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
17580c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg}
17680c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
17726328fc3933f377c47fb8b06feabbde5e12ed650jamal/*
17826328fc3933f377c47fb8b06feabbde5e12ed650jamal * The controller sends one nlmsg per family
17926328fc3933f377c47fb8b06feabbde5e12ed650jamal*/
18065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimstatic int print_ctrl(const struct sockaddr_nl *who, struct nlmsghdr *n,
18165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		      void *arg)
18265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim{
18365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct rtattr *tb[CTRL_ATTR_MAX + 1];
18465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct genlmsghdr *ghdr = NLMSG_DATA(n);
18565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	int len = n->nlmsg_len;
18665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct rtattr *attrs;
18765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	FILE *fp = (FILE *) arg;
18881c61790d5927dc6ca168b2183000a3efc7bc493Stephen Hemminger	__u32 ctrl_v = 0x1;
18965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
19065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (n->nlmsg_type !=  GENL_ID_CTRL) {
19165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		fprintf(stderr, "Not a controller message, nlmsg_len=%d "
19265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			"nlmsg_type=0x%x\n", n->nlmsg_len, n->nlmsg_type);
19365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return 0;
19465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
19565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
19665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (ghdr->cmd != CTRL_CMD_GETFAMILY &&
19765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	    ghdr->cmd != CTRL_CMD_DELFAMILY &&
19880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	    ghdr->cmd != CTRL_CMD_NEWFAMILY &&
19980c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	    ghdr->cmd != CTRL_CMD_NEWMCAST_GRP &&
20080c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	    ghdr->cmd != CTRL_CMD_DELMCAST_GRP) {
20180c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
20265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return 0;
20365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
20465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
20565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	len -= NLMSG_LENGTH(GENL_HDRLEN);
20665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
20765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (len < 0) {
20865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		fprintf(stderr, "wrong controller message len %d\n", len);
20965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return -1;
21065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
21165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
21265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
21365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);
21465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
21565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (tb[CTRL_ATTR_FAMILY_NAME]) {
21665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		char *name = RTA_DATA(tb[CTRL_ATTR_FAMILY_NAME]);
21726328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, "\nName: %s\n",name);
21865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
21965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (tb[CTRL_ATTR_FAMILY_ID]) {
22065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		__u16 *id = RTA_DATA(tb[CTRL_ATTR_FAMILY_ID]);
22126328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, "\tID: 0x%x ",*id);
22226328fc3933f377c47fb8b06feabbde5e12ed650jamal	}
22326328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (tb[CTRL_ATTR_VERSION]) {
22426328fc3933f377c47fb8b06feabbde5e12ed650jamal		__u32 *v = RTA_DATA(tb[CTRL_ATTR_VERSION]);
22526328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " Version: 0x%x ",*v);
22626328fc3933f377c47fb8b06feabbde5e12ed650jamal		ctrl_v = *v;
22765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
22826328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (tb[CTRL_ATTR_HDRSIZE]) {
22926328fc3933f377c47fb8b06feabbde5e12ed650jamal		__u32 *h = RTA_DATA(tb[CTRL_ATTR_HDRSIZE]);
23026328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " header size: %d ",*h);
23126328fc3933f377c47fb8b06feabbde5e12ed650jamal	}
23226328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (tb[CTRL_ATTR_MAXATTR]) {
23326328fc3933f377c47fb8b06feabbde5e12ed650jamal		__u32 *ma = RTA_DATA(tb[CTRL_ATTR_MAXATTR]);
23426328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, " max attribs: %d ",*ma);
23526328fc3933f377c47fb8b06feabbde5e12ed650jamal	}
23626328fc3933f377c47fb8b06feabbde5e12ed650jamal	/* end of family definitions .. */
23726328fc3933f377c47fb8b06feabbde5e12ed650jamal	fprintf(fp,"\n");
23826328fc3933f377c47fb8b06feabbde5e12ed650jamal	if (tb[CTRL_ATTR_OPS]) {
23926328fc3933f377c47fb8b06feabbde5e12ed650jamal		struct rtattr *tb2[GENL_MAX_FAM_OPS];
24026328fc3933f377c47fb8b06feabbde5e12ed650jamal		int i=0;
24126328fc3933f377c47fb8b06feabbde5e12ed650jamal		parse_rtattr_nested(tb2, GENL_MAX_FAM_OPS, tb[CTRL_ATTR_OPS]);
24226328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp, "\tcommands supported: \n");
24326328fc3933f377c47fb8b06feabbde5e12ed650jamal		for (i = 0; i < GENL_MAX_FAM_OPS; i++) {
24426328fc3933f377c47fb8b06feabbde5e12ed650jamal			if (tb2[i]) {
24526328fc3933f377c47fb8b06feabbde5e12ed650jamal				fprintf(fp, "\t\t#%d: ", i);
24626328fc3933f377c47fb8b06feabbde5e12ed650jamal				if (0 > print_ctrl_cmds(fp, tb2[i], ctrl_v)) {
24726328fc3933f377c47fb8b06feabbde5e12ed650jamal					fprintf(fp, "Error printing command\n");
24826328fc3933f377c47fb8b06feabbde5e12ed650jamal				}
24926328fc3933f377c47fb8b06feabbde5e12ed650jamal				/* for next command */
25026328fc3933f377c47fb8b06feabbde5e12ed650jamal				fprintf(fp,"\n");
25126328fc3933f377c47fb8b06feabbde5e12ed650jamal			}
25226328fc3933f377c47fb8b06feabbde5e12ed650jamal		}
25365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
25426328fc3933f377c47fb8b06feabbde5e12ed650jamal		/* end of family::cmds definitions .. */
25526328fc3933f377c47fb8b06feabbde5e12ed650jamal		fprintf(fp,"\n");
25626328fc3933f377c47fb8b06feabbde5e12ed650jamal	}
25780c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
25880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	if (tb[CTRL_ATTR_MCAST_GROUPS]) {
25980c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		struct rtattr *tb2[GENL_MAX_FAM_GRPS + 1];
26080c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		int i;
26180c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
26280c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		parse_rtattr_nested(tb2, GENL_MAX_FAM_GRPS,
26380c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg				    tb[CTRL_ATTR_MCAST_GROUPS]);
26480c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		fprintf(fp, "\tmulticast groups:\n");
26580c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
26680c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		for (i = 0; i < GENL_MAX_FAM_GRPS; i++) {
26780c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg			if (tb2[i]) {
26880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg				fprintf(fp, "\t\t#%d: ", i);
26980c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg				if (0 > print_ctrl_grp(fp, tb2[i], ctrl_v))
27080c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg					fprintf(fp, "Error printing group\n");
27180c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg				/* for next group */
27280c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg				fprintf(fp,"\n");
27380c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg			}
27480c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		}
27580c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
27680c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		/* end of family::groups definitions .. */
27780c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg		fprintf(fp,"\n");
27880c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg	}
27980c05b0976be86308e92b2837e0a94c484e388b4Johannes Berg
28065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	fflush(fp);
28165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	return 0;
28265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim}
28365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
28465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimstatic int ctrl_list(int cmd, int argc, char **argv)
28565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim{
28665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct rtnl_handle rth;
28765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct nlmsghdr *nlh;
28865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct genlmsghdr *ghdr;
28965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	int ret = -1;
29065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	char d[GENL_NAMSIZ];
29165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct {
29265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		struct nlmsghdr         n;
29365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		char                    buf[4096];
29465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	} req;
29565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
29665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	memset(&req, 0, sizeof(req));
29765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
29865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh = &req.n;
29965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
30065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
30165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	nlh->nlmsg_type = GENL_ID_CTRL;
30265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
30365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	ghdr = NLMSG_DATA(&req.n);
30465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	ghdr->cmd = CTRL_CMD_GETFAMILY;
30565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
30665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
30765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		fprintf(stderr, "Cannot open generic netlink socket\n");
30865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		exit(1);
30965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
31065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
31165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (cmd == CTRL_CMD_GETFAMILY) {
31265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		if (argc != 2) {
31365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			fprintf(stderr, "Wrong number of params\n");
31465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			return -1;
31565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
31665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
31765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		if (matches(*argv, "name") == 0) {
31865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			NEXT_ARG();
31965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			strncpy(d, *argv, sizeof (d) - 1);
32065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME,
32165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim				  d, strlen(d) + 1);
32265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		} else if (matches(*argv, "id") == 0) {
32365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			__u16 id;
32465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			NEXT_ARG();
32565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			if (get_u16(&id, *argv, 0)) {
32665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim				fprintf(stderr, "Illegal \"id\"\n");
32765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim				goto ctrl_done;
32865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			}
32965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
33065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			addattr_l(nlh, 128, CTRL_ATTR_FAMILY_ID, &id, 2);
33165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
33265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		} else {
33365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			fprintf(stderr, "Wrong params\n");
33465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			goto ctrl_done;
33565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
33665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
337cd70f3f522e04b4d2fa80ae10292379bf223a53bStephen Hemminger		if (rtnl_talk(&rth, nlh, 0, 0, nlh) < 0) {
33865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			fprintf(stderr, "Error talking to the kernel\n");
33965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			goto ctrl_done;
34065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
34165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
34265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		if (print_ctrl(NULL, nlh, (void *) stdout) < 0) {
34365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			fprintf(stderr, "Dump terminated\n");
34465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			goto ctrl_done;
34565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
34665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
34765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
34865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
34965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (cmd == CTRL_CMD_UNSPEC) {
35065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		nlh->nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
35165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		nlh->nlmsg_seq = rth.dump = ++rth.seq;
35265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
3536cf8398f5f487762586801c25539d8fe5bb33b39Stephen Hemminger		if (rtnl_send(&rth, nlh, nlh->nlmsg_len) < 0) {
35465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			perror("Failed to send dump request\n");
35565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim			goto ctrl_done;
35665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		}
35765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
358cd70f3f522e04b4d2fa80ae10292379bf223a53bStephen Hemminger		rtnl_dump_filter(&rth, print_ctrl, stdout);
35965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
36065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim        }
36165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
36265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	ret = 0;
36365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimctrl_done:
36465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	rtnl_close(&rth);
36565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	return ret;
36665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim}
36765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
36865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimstatic int ctrl_listen(int argc, char **argv)
36965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim{
37065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	struct rtnl_handle rth;
37165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
37265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (rtnl_open_byproto(&rth, nl_mgrp(GENL_ID_CTRL), NETLINK_GENERIC) < 0) {
37365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		fprintf(stderr, "Canot open generic netlink socket\n");
37465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return -1;
37565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
37665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
37765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (rtnl_listen(&rth, print_ctrl, (void *) stdout) < 0)
37865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return -1;
37965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
38065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	return 0;
38165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim}
38265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
38365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimstatic int parse_ctrl(struct genl_util *a, int argc, char **argv)
38465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim{
38565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	argv++;
38665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (--argc <= 0) {
38765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		fprintf(stderr, "wrong controller params\n");
38865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return -1;
38965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	}
39065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
39165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (matches(*argv, "monitor") == 0)
39265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return ctrl_listen(argc-1, argv+1);
39365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (matches(*argv, "get") == 0)
39465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return ctrl_list(CTRL_CMD_GETFAMILY, argc-1, argv+1);
39565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (matches(*argv, "list") == 0 ||
39665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	    matches(*argv, "show") == 0 ||
39765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	    matches(*argv, "lst") == 0)
39865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return ctrl_list(CTRL_CMD_UNSPEC, argc-1, argv+1);
39965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	if (matches(*argv, "help") == 0)
40065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		return usage();
40165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
40265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	fprintf(stderr, "ctrl command \"%s\" is unknown, try \"ctrl -help\".\n",
40365018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim		*argv);
40465018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
40565018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	return -1;
40665018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim}
40765018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim
40865018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salimstruct genl_util ctrl_genl_util = {
40965018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	.name = "ctrl",
41065018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	.parse_genlopt = parse_ctrl,
41165018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim	.print_genlopt = print_ctrl,
41265018ae43b14c8157bbe05473d76635626177b87Jamal Hadi Salim};
413