summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-03-30 10:27:21 +0200
committerJiri Olsa <Jiri Olsa jolsa@redhat.com>2010-03-30 10:27:21 +0200
commit7f4dc168b6cfa82682a0235c4e426e43950ed1a9 (patch)
tree9f011a381024a3c19f9bd367b5468fbc545e6b1a
parentb19b72eebbe375efe062c47468155d986db57c1f (diff)
downloadtsnif-7f4dc168b6cfa82682a0235c4e426e43950ed1a9.tar.gz
tsnif-7f4dc168b6cfa82682a0235c4e426e43950ed1a9.tar.xz
tsnif-7f4dc168b6cfa82682a0235c4e426e43950ed1a9.zip
added ack processing
-rw-r--r--include/linux/tsnif.h1
-rw-r--r--src/fsm.c105
-rw-r--r--src/fsm.h2
-rw-r--r--src/intf.c14
-rw-r--r--src/intf.h7
-rw-r--r--src/trans-libnl.c101
-rw-r--r--src/trans.h7
-rw-r--r--src/tsnif.c9
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 {
diff --git a/src/fsm.c b/src/fsm.c
index e29bd16..c8eebaf 100644
--- a/src/fsm.c
+++ b/src/fsm.c
@@ -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;
+}
diff --git a/src/fsm.h b/src/fsm.h
index cca3b5a..9d1b7ff 100644
--- a/src/fsm.h
+++ b/src/fsm.h
@@ -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 */
diff --git a/src/intf.c b/src/intf.c
index fde18a3..8cb7e02 100644
--- a/src/intf.c
+++ b/src/intf.c
@@ -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;
diff --git a/src/intf.h b/src/intf.h
index a40e9c4..a6b6577 100644
--- a/src/intf.h
+++ b/src/intf.h
@@ -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;