summaryrefslogtreecommitdiffstats
path: root/src/trans-libnl.c
diff options
context:
space:
mode:
authorJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-03-25 08:42:19 +0100
committerJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-03-25 08:42:19 +0100
commit24e91dc5627b181f90c800cf613614e5787e76da (patch)
tree630eb6e8b18492b5d3c3624ab94be3f3e21bc8c0 /src/trans-libnl.c
downloadtsnif-24e91dc5627b181f90c800cf613614e5787e76da.tar.gz
tsnif-24e91dc5627b181f90c800cf613614e5787e76da.tar.xz
tsnif-24e91dc5627b181f90c800cf613614e5787e76da.zip
initial commit
Diffstat (limited to 'src/trans-libnl.c')
-rw-r--r--src/trans-libnl.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/trans-libnl.c b/src/trans-libnl.c
new file mode 100644
index 0000000..e692cd9
--- /dev/null
+++ b/src/trans-libnl.c
@@ -0,0 +1,195 @@
+
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/tsnif.h>
+#include <asm/errno.h>
+
+#include "intf.h"
+#include "trans.h"
+
+TSNIF_POLICY(gnl_policy);
+
+static int ack_cb(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+static int seq_cb(struct nl_msg *msg, void *arg)
+{
+ /* FIXME Our sequence numbers of DATA packets are zero,
+ * so let disable the seq check completely */
+ return NL_OK;
+}
+
+#define CB_RET(err) (err ? NL_STOP : NL_OK)
+
+int err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
+{
+ struct nlmsghdr *nlh = &nlerr->msg;
+ struct genlmsghdr *ghdr = nlmsg_data(nlh);
+ struct nlattr *attrs[TSNIF_ATTR_MAX + 1];
+ struct trans_handle *h = arg;
+ struct trans_msg m;
+
+ genlmsg_parse(nlh, 0, attrs, TSNIF_ATTR_MAX, gnl_policy);
+ memset(&m, 0x0, sizeof(m));
+
+ if (attrs[TSNIF_ATTR_IDX])
+ m.idx = nla_get_u32(attrs[TSNIF_ATTR_IDX]);
+
+ if (attrs[TSNIF_ATTR_TYPE])
+ m.type = nla_get_u32(attrs[TSNIF_ATTR_TYPE]);
+
+ m.cmd = ghdr->cmd;
+ m.err = 1;
+ m.error = nlerr->error;
+
+ TSNIF_DEBUG("got err %d for cmd %d, type %d, idx %d\n",
+ nlerr->error, m.cmd, m.idx, m.type);
+
+ return CB_RET(h->cb(h, &m));
+}
+
+static int parse_cb(struct nl_msg *msg, void *arg)
+{
+ struct nlmsghdr *nlh = nlmsg_hdr(msg);
+ struct genlmsghdr *ghdr = nlmsg_data(nlh);
+ struct nlattr *attrs[TSNIF_ATTR_MAX + 1];
+ struct trans_handle *h = arg;
+ struct trans_msg m;
+
+ genlmsg_parse(nlh, 0, attrs, TSNIF_ATTR_MAX, gnl_policy);
+ memset(&m, 0x0, sizeof(m));
+
+ if (attrs[TSNIF_ATTR_IDX])
+ m.idx = nla_get_u32(attrs[TSNIF_ATTR_IDX]);
+
+ if (attrs[TSNIF_ATTR_TYPE])
+ m.type = nla_get_u32(attrs[TSNIF_ATTR_TYPE]);
+
+ m.cmd = ghdr->cmd;
+
+ TSNIF_DEBUG("got cmd %d\n", m.cmd);
+
+ switch(ghdr->cmd) {
+ case TSNIF_CMD_RELEASE:
+ case TSNIF_CMD_TTY_CREATE:
+ case TSNIF_CMD_TTY_RELEASE:
+ /* nothing to do, but not an error */
+ break;
+
+ case TSNIF_CMD_MGROUP:
+ case TSNIF_CMD_TGROUP:
+ m.group = nla_get_u32(attrs[TSNIF_ATTR_GROUP]);
+ break;
+
+ case TSNIF_CMD_DATA:
+ {
+ m.data.ptr = nla_data(attrs[TSNIF_ATTR_DATA]);
+ m.data.len = nla_len(attrs[TSNIF_ATTR_DATA]);
+ m.data.flags = nla_get_u32(attrs[TSNIF_ATTR_FLAGS]);
+ break;
+ }
+
+ default:
+ /* we are not supposed to get anything else */
+ return -1;
+ }
+
+ return CB_RET(h->cb(h, &m));
+}
+
+int trans_init(struct trans_handle *h, trans_cb_t cb)
+{
+ struct nl_handle *sock;
+ int family;
+ int err;
+
+ memset(h, 0x0, sizeof(*h));
+
+ sock = nl_handle_alloc();
+ if (!sock)
+ return nl_get_errno();
+
+ err = genl_connect(sock);
+ if (err)
+ return err;
+
+ TSNIF_DEBUG("connected\n");
+
+ family = genl_ctrl_resolve(sock, "tsnif");
+ if (family < 0)
+ return family;
+
+ TSNIF_DEBUG("tsnif module found\n");
+
+ nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, parse_cb, h);
+ nl_socket_modify_cb(sock, NL_CB_SEND_ACK, NL_CB_CUSTOM, ack_cb, h);
+ nl_socket_modify_cb(sock, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_cb, h);
+ nl_cb_err(nl_socket_get_cb(sock), NL_CB_CUSTOM, err_cb, h);
+
+ h->sock = sock;
+ h->family = family;
+ h->cb = cb;
+ return 0;
+}
+
+int trans_close(struct trans_handle *h)
+{
+ nl_handle_destroy(h->sock);
+ return 0;
+}
+
+int trans_process(struct trans_handle *h)
+{
+ int err;
+
+ err = nl_recvmsgs_default(h->sock);
+ if (err)
+ TSNIF_DEBUG("got error: %s\n", nl_geterror());
+
+ return err;
+}
+
+int trans_send(struct trans_handle *h, struct trans_msg *m)
+{
+ struct nl_msg *msg;
+ int err;
+
+ TSNIF_DEBUG("sending cmd = %d\n", m->cmd);
+
+ if ((m->cmd != TSNIF_CMD_ATTACH) &&
+ (m->cmd != TSNIF_CMD_DETACH) &&
+ (m->cmd != TSNIF_CMD_MGROUP))
+ return -EINVAL;
+
+ msg = nlmsg_alloc();
+ genlmsg_put(msg,
+ NL_AUTO_PID, NL_AUTO_SEQ,
+ h->family, 0, NLM_F_ECHO,
+ m->cmd, TSNIF_VERSION);
+
+ if ((m->cmd == TSNIF_CMD_ATTACH) ||
+ (m->cmd == TSNIF_CMD_DETACH)) {
+ nla_put_u32(msg, TSNIF_ATTR_TYPE, m->type);
+ nla_put_u32(msg, TSNIF_ATTR_IDX, m->idx);
+ }
+
+ err = nl_send_auto_complete(h->sock, msg);
+ nlmsg_free(msg);
+
+ TSNIF_DEBUG("sent result %d\n", err);
+ return err > 0 ? 0 : err;
+}
+
+int trans_group(struct trans_handle *h, int group)
+{
+ return nl_socket_add_membership(h->sock, group);
+}
+
+int trans_fd(struct trans_handle *h)
+{
+ return nl_socket_get_fd(h->sock);
+}