1 /* 2 * msg.c Messaging (netlink) helper functions. 3 * 4 * This program is free software; you can redistribute 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: Richard Alpe <richard.alpe (at) ericsson.com> 10 */ 11 12 #include <stdio.h> 13 #include <time.h> 14 #include <errno.h> 15 16 #include <linux/tipc_netlink.h> 17 #include <linux/tipc.h> 18 #include <linux/genetlink.h> 19 #include <libmnl/libmnl.h> 20 21 #include "msg.h" 22 23 int parse_attrs(const struct nlattr *attr, void *data) 24 { 25 const struct nlattr **tb = data; 26 int type = mnl_attr_get_type(attr); 27 28 tb[type] = attr; 29 30 return MNL_CB_OK; 31 } 32 33 static int family_id_cb(const struct nlmsghdr *nlh, void *data) 34 { 35 struct nlattr *tb[CTRL_ATTR_MAX + 1] = {}; 36 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 37 int *id = data; 38 39 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, tb); 40 if (!tb[CTRL_ATTR_FAMILY_ID]) 41 return MNL_CB_ERROR; 42 43 *id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]); 44 45 return MNL_CB_OK; 46 } 47 48 static struct mnl_socket *msg_send(struct nlmsghdr *nlh) 49 { 50 int ret; 51 struct mnl_socket *nl; 52 53 nl = mnl_socket_open(NETLINK_GENERIC); 54 if (nl == NULL) { 55 perror("mnl_socket_open"); 56 return NULL; 57 } 58 59 ret = mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID); 60 if (ret < 0) { 61 perror("mnl_socket_bind"); 62 return NULL; 63 } 64 65 ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len); 66 if (ret < 0) { 67 perror("mnl_socket_send"); 68 return NULL; 69 } 70 71 return nl; 72 } 73 74 static int msg_recv(struct mnl_socket *nl, mnl_cb_t callback, void *data, int seq) 75 { 76 int ret; 77 unsigned int portid; 78 char buf[MNL_SOCKET_BUFFER_SIZE]; 79 80 portid = mnl_socket_get_portid(nl); 81 82 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 83 while (ret > 0) { 84 ret = mnl_cb_run(buf, ret, seq, portid, callback, data); 85 if (ret <= 0) 86 break; 87 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 88 } 89 if (ret == -1) 90 perror("error"); 91 92 mnl_socket_close(nl); 93 94 return ret; 95 } 96 97 static int msg_query(struct nlmsghdr *nlh, mnl_cb_t callback, void *data) 98 { 99 unsigned int seq; 100 struct mnl_socket *nl; 101 102 seq = time(NULL); 103 nlh->nlmsg_seq = seq; 104 105 nl = msg_send(nlh); 106 if (!nl) 107 return -ENOTSUP; 108 109 return msg_recv(nl, callback, data, seq); 110 } 111 112 static int get_family(void) 113 { 114 int err; 115 int nl_family; 116 struct nlmsghdr *nlh; 117 struct genlmsghdr *genl; 118 char buf[MNL_SOCKET_BUFFER_SIZE]; 119 120 nlh = mnl_nlmsg_put_header(buf); 121 nlh->nlmsg_type = GENL_ID_CTRL; 122 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 123 124 genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); 125 genl->cmd = CTRL_CMD_GETFAMILY; 126 genl->version = 1; 127 128 mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL); 129 mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, TIPC_GENL_V2_NAME); 130 131 if ((err = msg_query(nlh, family_id_cb, &nl_family))) 132 return err; 133 134 return nl_family; 135 } 136 137 int msg_doit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data) 138 { 139 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 140 return msg_query(nlh, callback, data); 141 } 142 143 int msg_dumpit(struct nlmsghdr *nlh, mnl_cb_t callback, void *data) 144 { 145 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 146 return msg_query(nlh, callback, data); 147 } 148 149 struct nlmsghdr *msg_init(char *buf, int cmd) 150 { 151 int family; 152 struct nlmsghdr *nlh; 153 struct genlmsghdr *genl; 154 155 family = get_family(); 156 if (family <= 0) { 157 fprintf(stderr, 158 "Unable to get TIPC nl family id (module loaded?)\n"); 159 return NULL; 160 } 161 162 nlh = mnl_nlmsg_put_header(buf); 163 nlh->nlmsg_type = family; 164 165 genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr)); 166 genl->cmd = cmd; 167 genl->version = 1; 168 169 return nlh; 170 } 171