#include #include #include #include #include #include #include "intf.h" #include "trans.h" #include "debug.h" #ifndef SOL_NETLINK #define SOL_NETLINK 270 #endif TSNIF_POLICY(gnl_policy); 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; } static int process_cb(struct trans_handle *h, struct trans_msg *m, struct nlmsghdr *nlh) { struct genlmsghdr *ghdr = nlmsg_data(nlh); struct nlattr *attrs[TSNIF_ATTR_MAX + 1]; genlmsg_parse(nlh, 0, attrs, TSNIF_ATTR_MAX, gnl_policy); /* parse the message and get all the attributes we can */ 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]); if (attrs[TSNIF_ATTR_GROUP]) m->group = nla_get_u32(attrs[TSNIF_ATTR_GROUP]); if (attrs[TSNIF_ATTR_DATA]) { m->data.ptr = nla_data(attrs[TSNIF_ATTR_DATA]); m->data.len = nla_len(attrs[TSNIF_ATTR_DATA]); } if (attrs[TSNIF_ATTR_TIME]) { struct timespec *time; time = (struct timespec*) nla_data(attrs[TSNIF_ATTR_TIME]); m->data.time = *(time); } if (attrs[TSNIF_ATTR_WS]) { struct winsize *ws; ws = (struct winsize*) nla_data(attrs[TSNIF_ATTR_WS]); m->data.ws = *(ws); } if (attrs[TSNIF_ATTR_FLAGS]) m->data.flags = nla_get_u32(attrs[TSNIF_ATTR_FLAGS]); m->cmd = ghdr->cmd; TSNIF_DEBUG(TRANS, "got cmd %d, type %d, idx %d, " "ack %d, err %d\n", m->cmd, m->type, m->idx, m->ack, m->err); return h->cb(h, m) ? NL_STOP : NL_OK; } static int err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg) { struct trans_msg m; memset(&m, 0x0, sizeof(m)); if (nlerr->error == TSNIF_OK) m.ack = 1; else { m.err = 1; m.error = nlerr->error; } TSNIF_DEBUG(TRANS, "got error cb - ack %d, err %d, error %d\n", m.ack, m.err, m.error); return process_cb(arg, &m, &nlerr->msg); } static int parse_cb(struct nl_msg *msg, void *arg) { struct trans_msg m; TSNIF_DEBUG(TRANS, "got parse cb\n"); memset(&m, 0x0, sizeof(m)); return process_cb(arg, &m, nlmsg_hdr(msg)); } static int set_no_enobufs(struct trans_handle *h) { int val = 1; return setsockopt(trans_fd(h), SOL_NETLINK, NETLINK_NO_ENOBUFS, &val, sizeof(val)); } 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(TRANS, "connected\n"); family = genl_ctrl_resolve(sock, "tsnif"); if (family < 0) return family; TSNIF_DEBUG(TRANS, "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_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; err = set_no_enobufs(h); if (err) TSNIF_DEBUG(TRANS, "failed to set ENOBUFS, moving on...\n"); 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(TRANS, "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(TRANS, "sending cmd = %d\n", m->cmd); if ((m->cmd != TSNIF_CMD_ATTACH) && (m->cmd != TSNIF_CMD_DETACH) && (m->cmd != TSNIF_CMD_TTY_LIST) && (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(TRANS, "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); }