diff options
author | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2010-03-30 10:27:21 +0200 |
---|---|---|
committer | Jiri Olsa <Jiri Olsa jolsa@redhat.com> | 2010-03-30 10:27:21 +0200 |
commit | 7f4dc168b6cfa82682a0235c4e426e43950ed1a9 (patch) | |
tree | 9f011a381024a3c19f9bd367b5468fbc545e6b1a | |
parent | b19b72eebbe375efe062c47468155d986db57c1f (diff) | |
download | tsnif-7f4dc168b6cfa82682a0235c4e426e43950ed1a9.tar.gz tsnif-7f4dc168b6cfa82682a0235c4e426e43950ed1a9.tar.xz tsnif-7f4dc168b6cfa82682a0235c4e426e43950ed1a9.zip |
added ack processing
-rw-r--r-- | include/linux/tsnif.h | 1 | ||||
-rw-r--r-- | src/fsm.c | 105 | ||||
-rw-r--r-- | src/fsm.h | 2 | ||||
-rw-r--r-- | src/intf.c | 14 | ||||
-rw-r--r-- | src/intf.h | 7 | ||||
-rw-r--r-- | src/trans-libnl.c | 101 | ||||
-rw-r--r-- | src/trans.h | 7 | ||||
-rw-r--r-- | src/tsnif.c | 9 |
8 files changed, 166 insertions, 80 deletions
diff --git a/include/linux/tsnif.h b/include/linux/tsnif.h index 8582c1c..86e49fd 100644 --- a/include/linux/tsnif.h +++ b/include/linux/tsnif.h @@ -7,6 +7,7 @@ #endif #define TSNIF_VERSION 1 +#define TSNIF_OK 1 /* attributes */ enum { @@ -10,6 +10,8 @@ static int process_release(struct tsnif_handle *h, struct tsnif_term *term) if (!h->ops || !h->ops->cb_release) return -1; + term->state = TSNIF_INTF_STATE_DONE; + return h->ops->cb_release(term); } @@ -33,10 +35,37 @@ static int process_tgroup(struct tsnif_handle *h, struct tsnif_term *term, return err; } +static int process_data(struct tsnif_handle *h, + struct tsnif_term *term, + struct trans_msg *msg) +{ + struct tsnif_data data; + + TSNIF_DEBUG("type %d, idx %d\n", + term->type, term->idx); + + if (!h->ops || !h->ops->cb_data) + return -1; + + data.ptr = msg->data.ptr; + data.len = msg->data.len; + data.flags = msg->data.flags; + + return h->ops->cb_data(term, &data); +} + static int new(struct tsnif_handle *h, struct tsnif_term *term, struct trans_msg *msg) { + TSNIF_DEBUG("got data in the NEW state, something is wrong\n"); + return -1; +} + +static int attach(struct tsnif_handle *h, + struct tsnif_term *term, + struct trans_msg *msg) +{ int err = 0; switch(msg->cmd) { @@ -49,7 +78,11 @@ static int new(struct tsnif_handle *h, break; case TSNIF_CMD_ATTACH: - /* got ATTACH cmd without error ??? */ + /* got attach ack, do nothing */ + if (msg->ack) + break; + + /* got ATTACH cmd without error */ err = -EINVAL; if (!msg->err) break; @@ -64,31 +97,49 @@ static int new(struct tsnif_handle *h, return err; } -static int process_data(struct tsnif_handle *h, - struct tsnif_term *term, - struct trans_msg *msg) +static int detach(struct tsnif_handle *h, + struct tsnif_term *term, + struct trans_msg *msg) { - struct tsnif_data data; + int err = 0; - TSNIF_DEBUG("type %d, idx %d\n", - term->type, term->idx); + switch(msg->cmd) { + case TSNIF_CMD_DETACH: + if (msg->ack) { + term->state = TSNIF_INTF_STATE_DONE; + break; + } + err = -EINVAL; + if (!msg->err) + break; - if (!h->ops || !h->ops->cb_data) - return -1; + err = process_error(h, term, msg->error); + break; - data.ptr = msg->data.ptr; - data.len = msg->data.len; - data.flags = msg->data.flags; + case TSNIF_CMD_RELEASE: + err = process_release(h, term); + break; - return h->ops->cb_data(term, &data); -} + case TSNIF_CMD_DATA: + /* ignore DATA msg when in DETACH state */ + break; + default: + return -1; + } + + return err; +} static int data(struct tsnif_handle *h, struct tsnif_term *term, struct trans_msg *msg) { int err = 0; + /* all ACKs should be ok in this state */ + if (msg->ack) + return 0; + switch(msg->cmd) { case TSNIF_CMD_RELEASE: err = process_release(h, term); @@ -116,6 +167,12 @@ int fsm_process(struct tsnif_handle *h, case TSNIF_INTF_STATE_NEW: return new(h, term, msg); + case TSNIF_INTF_STATE_ATTACH: + return attach(h, term, msg); + + case TSNIF_INTF_STATE_DETACH: + return detach(h, term, msg); + case TSNIF_INTF_STATE_DATA: return data(h, term, msg); @@ -125,3 +182,23 @@ int fsm_process(struct tsnif_handle *h, return 0; } + +int fsm_send(struct tsnif_term *term, int cmd) +{ + switch(cmd) { + case TSNIF_CMD_ATTACH: + if (term->state != TSNIF_INTF_STATE_NEW) + return -1; + + term->state = TSNIF_INTF_STATE_ATTACH; + break; + + case TSNIF_CMD_DETACH: + if (term->state != TSNIF_INTF_STATE_DATA) + return -1; + + term->state = TSNIF_INTF_STATE_DETACH; + } + + return 0; +} @@ -6,4 +6,6 @@ int fsm_process(struct tsnif_handle *h, struct tsnif_term *term, struct trans_msg *msg); +int fsm_send(struct tsnif_term *term, int cmd); + #endif /* !FSM_H */ @@ -19,10 +19,13 @@ static struct tsnif_term *term_find(struct tsnif_handle *h, int type, int idx) return NULL; } -static int notify_cb(struct tsnif_handle *h, struct trans_msg *msg) +static int process_notify(struct tsnif_handle *h, struct trans_msg *msg) { struct tsnif_term term; + if (msg->ack) + return 0; + if (!h->ops || !h->ops->cb_notify) return -1; @@ -37,6 +40,9 @@ static int notify_cb(struct tsnif_handle *h, struct trans_msg *msg) static int process_mgroup(struct tsnif_handle *h, struct trans_msg *msg) { + if (msg->ack) + return 0; + return trans_group(&h->trans, msg->group); } @@ -54,7 +60,7 @@ static int trans_cb(struct trans_handle *h, struct trans_msg *msg) switch(msg->cmd) { case TSNIF_CMD_TTY_CREATE: case TSNIF_CMD_TTY_RELEASE: - return notify_cb(handle, msg); + return process_notify(handle, msg); case TSNIF_CMD_MGROUP: return process_mgroup(handle, msg); @@ -141,7 +147,7 @@ int tsnif_attach(struct tsnif_term *term) TSNIF_DEBUG("type %d, idx %d\n", term->type, term->idx); - if (term->state != TSNIF_INTF_STATE_NEW) { + if (fsm_send(term, TSNIF_CMD_ATTACH)) { TSNIF_DEBUG("wrong state (%d) skiping detach\n", term->state); return -1; @@ -161,7 +167,7 @@ int tsnif_detach(struct tsnif_term *term) TSNIF_DEBUG("type %d, idx %d\n", term->type, term->idx); - if (term->state != TSNIF_INTF_STATE_DATA) { + if (fsm_send(term, TSNIF_CMD_DETACH)) { TSNIF_DEBUG("wrong state (%d) skiping detach\n", term->state); return -1; @@ -10,8 +10,15 @@ #include "trans.h" enum { + /* created, added to the list */ TSNIF_INTF_STATE_NEW = 1, + /* attach is sent, waiting for TGROUP msg */ + TSNIF_INTF_STATE_ATTACH, + /* detach is sent, waiting for ack */ + TSNIF_INTF_STATE_DETACH, + /* got TGROUP msg, receiving DATA msg */ TSNIF_INTF_STATE_DATA, + /* got detach ack, released */ TSNIF_INTF_STATE_DONE, }; diff --git a/src/trans-libnl.c b/src/trans-libnl.c index e49407d..d4b814b 100644 --- a/src/trans-libnl.c +++ b/src/trans-libnl.c @@ -15,11 +15,6 @@ 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, @@ -27,82 +22,69 @@ static int seq_cb(struct nl_msg *msg, void *arg) return NL_OK; } -#define CB_RET(err) (err ? NL_STOP : NL_OK) - -int err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg) +static int process_cb(struct trans_handle *h, struct trans_msg *m, + struct nlmsghdr *nlh) { - 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)); + /* parse the message and get all the attributes we can */ if (attrs[TSNIF_ATTR_IDX]) - m.idx = nla_get_u32(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->type = nla_get_u32(attrs[TSNIF_ATTR_TYPE]); - m.cmd = ghdr->cmd; - m.err = 1; - m.error = nlerr->error; + if (attrs[TSNIF_ATTR_GROUP]) + m->group = nla_get_u32(attrs[TSNIF_ATTR_GROUP]); - TSNIF_DEBUG("got err %d for cmd %d, type %d, idx %d\n", - nlerr->error, m.cmd, m.idx, m.type); + 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_FLAGS]) + m->data.flags = nla_get_u32(attrs[TSNIF_ATTR_FLAGS]); + + m->cmd = ghdr->cmd; + + TSNIF_DEBUG("got cmd %d, type %d, idx %d, " + "ack %d, err %d\n", + m->cmd, m->idx, m->type, + m->ack, m->err); - return CB_RET(h->cb(h, &m)); + return h->cb(h, m) ? NL_STOP : NL_OK; } -static int parse_cb(struct nl_msg *msg, void *arg) +static int err_cb(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, 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)); + TSNIF_DEBUG("got error cb\n"); - if (attrs[TSNIF_ATTR_IDX]) - m.idx = nla_get_u32(attrs[TSNIF_ATTR_IDX]); + memset(&m, 0x0, sizeof(m)); - 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; + if (nlerr->error == TSNIF_OK) + m.ack = 1; + else { + m.err = 1; + m.error = nlerr->error; } - default: - /* we are not supposed to get anything else */ - return -1; - } + return process_cb(arg, &m, &nlerr->msg); +} + +static int parse_cb(struct nl_msg *msg, void *arg) +{ + struct trans_msg m; + + TSNIF_DEBUG("got parse cb\n"); + + memset(&m, 0x0, sizeof(m)); - return CB_RET(h->cb(h, &m)); + return process_cb(arg, &m, nlmsg_hdr(msg)); } static int set_no_enobufs(struct trans_handle *h) @@ -140,7 +122,6 @@ int trans_init(struct trans_handle *h, trans_cb_t cb) 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); diff --git a/src/trans.h b/src/trans.h index 38589d4..4778695 100644 --- a/src/trans.h +++ b/src/trans.h @@ -8,11 +8,18 @@ struct trans_msg; typedef int(*trans_cb_t)(struct trans_handle *h, struct trans_msg *msg); struct trans_msg { + /* netlink command */ int cmd; + + /* common attributes */ int type; int idx; + + /* flags indicating error/ack message */ int err; + int ack; + /* attributes based on cmd field */ union { /* data message */ struct { diff --git a/src/tsnif.c b/src/tsnif.c index d2bcc41..b6f4150 100644 --- a/src/tsnif.c +++ b/src/tsnif.c @@ -118,12 +118,13 @@ static int get_args(int argc, char **argv) static struct option long_options[] = { {"type", required_argument, 0, 't'}, {"idx", required_argument, 0, 'i'}, - {"version", no_argument, 0, 'V'}, + {"version", no_argument, 0, 'v'}, + {"debug", no_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; - c = getopt_long(argc, argv, "t:i:vh", + c = getopt_long(argc, argv, "t:i:vdh", long_options, &option_index); if (c == -1) @@ -150,6 +151,10 @@ static int get_args(int argc, char **argv) printf("tsnif "CONFIG_TSNIF_VER"\n"); break; + case 'd': + tsnif_debug = 1; + break; + case 'h': usage(); break; |