diff options
author | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2010-03-25 08:42:19 +0100 |
---|---|---|
committer | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2010-03-25 08:42:19 +0100 |
commit | 24e91dc5627b181f90c800cf613614e5787e76da (patch) | |
tree | 630eb6e8b18492b5d3c3624ab94be3f3e21bc8c0 /src/trans-libnl.c | |
download | tsnif-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.c | 195 |
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); +} |