#include #include #include #include #include #include #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); }