Julian Anastasov | 8afcc28 | 2012-09-11 12:04:33 +0300 | [diff] [blame] | 1 | /* |
| 2 | * libgenl.c GENL library |
| 3 | */ |
| 4 | |
| 5 | #include <stdio.h> |
| 6 | #include <stdlib.h> |
| 7 | #include <unistd.h> |
| 8 | |
| 9 | #include <linux/genetlink.h> |
| 10 | #include "libgenl.h" |
| 11 | |
| 12 | static int genl_parse_getfamily(struct nlmsghdr *nlh) |
| 13 | { |
| 14 | struct rtattr *tb[CTRL_ATTR_MAX + 1]; |
| 15 | struct genlmsghdr *ghdr = NLMSG_DATA(nlh); |
| 16 | int len = nlh->nlmsg_len; |
| 17 | struct rtattr *attrs; |
| 18 | |
| 19 | if (nlh->nlmsg_type != GENL_ID_CTRL) { |
| 20 | fprintf(stderr, "Not a controller message, nlmsg_len=%d " |
| 21 | "nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type); |
| 22 | return -1; |
| 23 | } |
| 24 | |
| 25 | len -= NLMSG_LENGTH(GENL_HDRLEN); |
| 26 | |
| 27 | if (len < 0) { |
| 28 | fprintf(stderr, "wrong controller message len %d\n", len); |
| 29 | return -1; |
| 30 | } |
| 31 | |
| 32 | if (ghdr->cmd != CTRL_CMD_NEWFAMILY) { |
| 33 | fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd); |
| 34 | return -1; |
| 35 | } |
| 36 | |
| 37 | attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN); |
| 38 | parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len); |
| 39 | |
| 40 | if (tb[CTRL_ATTR_FAMILY_ID] == NULL) { |
| 41 | fprintf(stderr, "Missing family id TLV\n"); |
| 42 | return -1; |
| 43 | } |
| 44 | |
| 45 | return rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]); |
| 46 | } |
| 47 | |
| 48 | int genl_resolve_family(struct rtnl_handle *grth, const char *family) |
| 49 | { |
Julian Anastasov | 328d482 | 2012-09-12 09:15:19 +0300 | [diff] [blame] | 50 | GENL_REQUEST(req, 1024, GENL_ID_CTRL, 0, 0, CTRL_CMD_GETFAMILY, |
| 51 | NLM_F_REQUEST); |
Julian Anastasov | 8afcc28 | 2012-09-11 12:04:33 +0300 | [diff] [blame] | 52 | |
Julian Anastasov | 328d482 | 2012-09-12 09:15:19 +0300 | [diff] [blame] | 53 | addattr_l(&req.n, sizeof(req), CTRL_ATTR_FAMILY_NAME, |
Julian Anastasov | 8afcc28 | 2012-09-11 12:04:33 +0300 | [diff] [blame] | 54 | family, strlen(family) + 1); |
| 55 | |
Stephen Hemminger | c079e12 | 2015-05-27 12:26:14 -0700 | [diff] [blame] | 56 | if (rtnl_talk(grth, &req.n, &req.n, sizeof(req)) < 0) { |
Julian Anastasov | 8afcc28 | 2012-09-11 12:04:33 +0300 | [diff] [blame] | 57 | fprintf(stderr, "Error talking to the kernel\n"); |
| 58 | return -2; |
| 59 | } |
| 60 | |
| 61 | return genl_parse_getfamily(&req.n); |
| 62 | } |
Sabrina Dubroca | 2b68cb7 | 2016-08-16 16:26:55 +0200 | [diff] [blame] | 63 | |
| 64 | int genl_init_handle(struct rtnl_handle *grth, const char *family, |
| 65 | int *genl_family) |
| 66 | { |
| 67 | if (*genl_family >= 0) |
| 68 | return 0; |
| 69 | |
| 70 | if (rtnl_open_byproto(grth, 0, NETLINK_GENERIC) < 0) { |
| 71 | fprintf(stderr, "Cannot open generic netlink socket\n"); |
| 72 | return -1; |
| 73 | } |
| 74 | |
| 75 | *genl_family = genl_resolve_family(grth, family); |
| 76 | if (*genl_family < 0) |
| 77 | return -1; |
| 78 | |
| 79 | return 0; |
| 80 | } |