#include #include "intf.h" #include "trans.h" #include "debug.h" 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; TSNIF_DEBUG(FSM, "type %d, idx %d\n", term->type, term->idx); return h->ops->cb_release(term); } static int process_error(struct tsnif_handle *h, struct tsnif_term *term, int err) { if (!h->ops || !h->ops->cb_err) return -1; return h->ops->cb_err(term, err); } static int process_tgroup(struct tsnif_handle *h, struct tsnif_term *term, int group) { int err; err = trans_group(&h->trans, group); term->state = err ? TSNIF_INTF_STATE_DONE : TSNIF_INTF_STATE_DATA; TSNIF_DEBUG(FSM, "adding group %d, err %d\n", group, err); return err; } static int process_data(struct tsnif_handle *h, struct tsnif_term *term, struct trans_msg *msg) { struct tsnif_data data; TSNIF_DEBUG(FSM, "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; data.time = msg->data.time; data.ws = msg->data.ws; return h->ops->cb_data(term, &data); } static int new(struct tsnif_handle *h, struct tsnif_term *term, struct trans_msg *msg) { TSNIF_DEBUG(FSM, "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) { case TSNIF_CMD_TGROUP: err = process_tgroup(h, term, msg->group); break; case TSNIF_CMD_ATTACH: /* got attach ack, do nothing */ if (msg->ack) break; /* got ATTACH cmd without error */ err = -EINVAL; if (!msg->err) break; err = process_error(h, term, msg->error); break; default: return -1; } return err; } static int detach(struct tsnif_handle *h, struct tsnif_term *term, struct trans_msg *msg) { int err = 0; switch(msg->cmd) { case TSNIF_CMD_DETACH: if (msg->ack) return process_release(h, term); err = -EINVAL; if (!msg->err) break; err = process_error(h, term, msg->error); break; 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_DATA: err = process_data(h, term, msg); break; default: return -1; } return err; } int fsm_process(struct tsnif_handle *h, struct tsnif_term *term, struct trans_msg *msg) { TSNIF_DEBUG(FSM, "got cmd %d for term type %d, idx %d, state %d\n", msg->cmd, term->type, term->idx, term->state); /* we can get the release command in any state, * so let's handle it globaly here */ if (msg->cmd == TSNIF_CMD_TTY_RELEASE) return process_release(h, term); switch(term->state) { 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); default: return -1; } 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; }