00001
00002
00003
00004
00005
00006
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 #include <time.h>
00011
00012 #include <libmnl/libmnl.h>
00013 #include <linux/genetlink.h>
00014
00015 static int parse_mc_grps_cb(const struct nlattr *attr, void *data)
00016 {
00017 const struct nlattr **tb = data;
00018 int type = mnl_attr_get_type(attr);
00019
00020
00021 if (mnl_attr_type_valid(attr, CTRL_ATTR_MCAST_GRP_MAX) < 0)
00022 return MNL_CB_OK;
00023
00024 switch(type) {
00025 case CTRL_ATTR_MCAST_GRP_ID:
00026 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
00027 perror("mnl_attr_validate");
00028 return MNL_CB_ERROR;
00029 }
00030 break;
00031 case CTRL_ATTR_MCAST_GRP_NAME:
00032 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
00033 perror("mnl_attr_validate");
00034 return MNL_CB_ERROR;
00035 }
00036 break;
00037 }
00038 tb[type] = attr;
00039 return MNL_CB_OK;
00040 }
00041
00042 static void parse_genl_mc_grps(struct nlattr *nested)
00043 {
00044 struct nlattr *pos;
00045
00046 mnl_attr_for_each_nested(pos, nested) {
00047 struct nlattr *tb[CTRL_ATTR_MCAST_GRP_MAX+1] = {};
00048
00049 mnl_attr_parse_nested(pos, parse_mc_grps_cb, tb);
00050 if (tb[CTRL_ATTR_MCAST_GRP_ID]) {
00051 printf("id-0x%x ",
00052 mnl_attr_get_u32(tb[CTRL_ATTR_MCAST_GRP_ID]));
00053 }
00054 if (tb[CTRL_ATTR_MCAST_GRP_NAME]) {
00055 printf("name: %s ",
00056 mnl_attr_get_str(tb[CTRL_ATTR_MCAST_GRP_NAME]));
00057 }
00058 printf("\n");
00059 }
00060 }
00061
00062 static int parse_family_ops_cb(const struct nlattr *attr, void *data)
00063 {
00064 const struct nlattr **tb = data;
00065 int type = mnl_attr_get_type(attr);
00066
00067 if (mnl_attr_type_valid(attr, CTRL_ATTR_OP_MAX) < 0)
00068 return MNL_CB_OK;
00069
00070 switch(type) {
00071 case CTRL_ATTR_OP_ID:
00072 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
00073 perror("mnl_attr_validate");
00074 return MNL_CB_ERROR;
00075 }
00076 break;
00077 case CTRL_ATTR_OP_MAX:
00078 break;
00079 default:
00080 return MNL_CB_OK;
00081 }
00082 tb[type] = attr;
00083 return MNL_CB_OK;
00084 }
00085
00086 static void parse_genl_family_ops(struct nlattr *nested)
00087 {
00088 struct nlattr *pos;
00089
00090 mnl_attr_for_each_nested(pos, nested) {
00091 struct nlattr *tb[CTRL_ATTR_OP_MAX+1] = {};
00092
00093 mnl_attr_parse_nested(pos, parse_family_ops_cb, tb);
00094 if (tb[CTRL_ATTR_OP_ID]) {
00095 printf("id-0x%x ",
00096 mnl_attr_get_u32(tb[CTRL_ATTR_OP_ID]));
00097 }
00098 if (tb[CTRL_ATTR_OP_MAX]) {
00099 printf("flags ");
00100 }
00101 printf("\n");
00102 }
00103 }
00104
00105 static int data_attr_cb(const struct nlattr *attr, void *data)
00106 {
00107 const struct nlattr **tb = data;
00108 int type = mnl_attr_get_type(attr);
00109
00110 if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
00111 return MNL_CB_OK;
00112
00113 switch(type) {
00114 case CTRL_ATTR_FAMILY_NAME:
00115 if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
00116 perror("mnl_attr_validate");
00117 return MNL_CB_ERROR;
00118 }
00119 break;
00120 case CTRL_ATTR_FAMILY_ID:
00121 if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0) {
00122 perror("mnl_attr_validate");
00123 return MNL_CB_ERROR;
00124 }
00125 break;
00126 case CTRL_ATTR_VERSION:
00127 case CTRL_ATTR_HDRSIZE:
00128 case CTRL_ATTR_MAXATTR:
00129 if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
00130 perror("mnl_attr_validate");
00131 return MNL_CB_ERROR;
00132 }
00133 break;
00134 case CTRL_ATTR_OPS:
00135 case CTRL_ATTR_MCAST_GROUPS:
00136 if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
00137 perror("mnl_attr_validate");
00138 return MNL_CB_ERROR;
00139 }
00140 break;
00141 }
00142 tb[type] = attr;
00143 return MNL_CB_OK;
00144 }
00145
00146 static int data_cb(const struct nlmsghdr *nlh, void *data)
00147 {
00148 struct nlattr *tb[CTRL_ATTR_MAX+1] = {};
00149 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
00150
00151 mnl_attr_parse(nlh, sizeof(*genl), data_attr_cb, tb);
00152 if (tb[CTRL_ATTR_FAMILY_NAME]) {
00153 printf("name=%s\t",
00154 mnl_attr_get_str(tb[CTRL_ATTR_FAMILY_NAME]));
00155 }
00156 if (tb[CTRL_ATTR_FAMILY_ID]) {
00157 printf("id=%u\t",
00158 mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]));
00159 }
00160 if (tb[CTRL_ATTR_VERSION]) {
00161 printf("version=%u\t",
00162 mnl_attr_get_u32(tb[CTRL_ATTR_VERSION]));
00163 }
00164 if (tb[CTRL_ATTR_HDRSIZE]) {
00165 printf("hdrsize=%u\t",
00166 mnl_attr_get_u32(tb[CTRL_ATTR_HDRSIZE]));
00167 }
00168 if (tb[CTRL_ATTR_MAXATTR]) {
00169 printf("maxattr=%u\t",
00170 mnl_attr_get_u32(tb[CTRL_ATTR_MAXATTR]));
00171 }
00172 if (tb[CTRL_ATTR_OPS]) {
00173 printf("\nops:\n");
00174 parse_genl_family_ops(tb[CTRL_ATTR_OPS]);
00175 }
00176 if (tb[CTRL_ATTR_MCAST_GROUPS]) {
00177 printf("\ngrps:\n");
00178 parse_genl_mc_grps(tb[CTRL_ATTR_MCAST_GROUPS]);
00179 }
00180 return MNL_CB_OK;
00181 }
00182
00183 int main(int argc, char *argv[])
00184 {
00185 struct mnl_socket *nl;
00186 char buf[MNL_SOCKET_BUFFER_SIZE];
00187 struct nlmsghdr *nlh;
00188 struct genlmsghdr *genl;
00189 int ret;
00190 unsigned int seq, portid;
00191
00192 if (argc != 2) {
00193 printf("%s [family name]\n", argv[0]);
00194 exit(EXIT_FAILURE);
00195 }
00196
00197 nlh = mnl_nlmsg_put_header(buf);
00198 nlh->nlmsg_type = GENL_ID_CTRL;
00199 nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
00200 nlh->nlmsg_seq = seq = time(NULL);
00201
00202 genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
00203 genl->cmd = CTRL_CMD_GETFAMILY;
00204 genl->version = 1;
00205
00206 mnl_attr_put_u32(nlh, CTRL_ATTR_FAMILY_ID, GENL_ID_CTRL);
00207 mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, argv[1]);
00208
00209 nl = mnl_socket_open(NETLINK_GENERIC);
00210 if (nl == NULL) {
00211 perror("mnl_socket_open");
00212 exit(EXIT_FAILURE);
00213 }
00214
00215 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
00216 perror("mnl_socket_bind");
00217 exit(EXIT_FAILURE);
00218 }
00219 portid = mnl_socket_get_portid(nl);
00220
00221 if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
00222 perror("mnl_socket_send");
00223 exit(EXIT_FAILURE);
00224 }
00225
00226 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
00227 while (ret > 0) {
00228 ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
00229 if (ret <= 0)
00230 break;
00231 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
00232 }
00233 if (ret == -1) {
00234 perror("error");
00235 exit(EXIT_FAILURE);
00236 }
00237
00238 mnl_socket_close(nl);
00239
00240 return 0;
00241 }