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