Ejemplo n.º 1
0
void
conn_fsm(struct connection *c, enum c_event event)
{
	int	i, ns;

	for (i = 0; fsm[i].action != NULL; i++) {
		if (c->state & fsm[i].state && event == fsm[i].event) {
			log_debug("conn_fsm[%s]: %s ev %s",
			    c->session->config.SessionName,
			    conn_state(c->state), conn_event(event));
			ns = fsm[i].action(c, event);
			if (ns == -1)
				/* XXX better please */
				fatalx("conn_fsm: action failed");
			log_debug("conn_fsm[%s]: new state %s",
			    c->session->config.SessionName, conn_state(ns));
			c->state = ns;
			return;
		}
	}
	log_warnx("conn_fsm[%s]: unhandled state transition [%s, %s]",
	    c->session->config.SessionName, conn_state(c->state),
	    conn_event(event));
	fatalx("bork bork bork");
}
Ejemplo n.º 2
0
/*
 * []----
 * | session_validate -- do what the name says
 * |
 * | At this point the connection has processed the login command so that
 * | we have InitiatorName and ISID at a minimum. Check to see if there
 * | are other sessions which match. If so, log that one out and proceed with
 * | this session. If nothing matches, then link this into a global list.
 * |
 * | Once we support multiple connections per session need to scan list
 * | to see if other connection have the same CID. If so, log out that
 * | connection.
 * []----
 */
Boolean_t
session_validate(iscsi_sess_t *s)
{
	iscsi_sess_t	*check;

	queue_prt(s->s_mgmtq, Q_SESS_NONIO,
	    "SES%x  %s ISID[%02x%02x%02x%02x%02x%02x]",
	    s->s_num, s->s_i_alias == NULL ? s->s_i_name : s->s_i_alias,
	    s->s_isid[0], s->s_isid[1], s->s_isid[2],
	    s->s_isid[3], s->s_isid[4], s->s_isid[5]);


	/*
	 * SessionType=Discovery which means no target name and therefore
	 * this is okay.
	 */
	if (s->s_t_name == NULL)
		return (True);

	(void) pthread_mutex_lock(&sess_mutex);
	for (check = sess_head; check; check = check->s_next) {
		/*
		 * Ignore ourselves in this check.
		 */
		if (check == s)
			continue;
		if ((check->s_t_name == NULL) ||
		    (strcmp(check->s_t_name, s->s_t_name) != 0))
			continue;
		if (strcmp(check->s_i_name, s->s_i_name) != 0)
			continue;
		if (check->s_conn_head->c_tpgt != s->s_conn_head->c_tpgt)
			continue;
		/*
		 * Section 5.3.5
		 * Session reinstatement is the process of the initiator
		 * logging in with an ISID that is possible active from
		 * the target's perspective. Thus implicitly logging out
		 * the session that corresponds to the ISID and
		 * reinstating a new iSCSI session in its place (with the
		 * same ISID).
		 */
		if (bcmp(check->s_isid, s->s_isid, 6) == 0) {
			queue_prt(s->s_mgmtq, Q_SESS_NONIO,
			    "SES%x  Implicit shutdown", check->s_num);
			if (check->s_conn_head->c_state == S5_LOGGED_IN)
				conn_state(check->s_conn_head, T8);
			else
				conn_state(check->s_conn_head, T7);
			break;
		}
	}
	(void) pthread_mutex_unlock(&sess_mutex);

	return (True);
}
Ejemplo n.º 3
0
static int conn_read(BIO *b, char *out, int outl)
	{
	int ret=0;
	BIO_CONNECT *data;

	data=(BIO_CONNECT *)b->ptr;
	if (data->state != BIO_CONN_S_OK)
		{
		ret=conn_state(b,data);
		if (ret <= 0)
				return(ret);
		}

	if (out != NULL)
		{
		clear_socket_error();
		ret=readsocket(b->num,out,outl);
		BIO_clear_retry_flags(b);
		if (ret <= 0)
			{
			if (BIO_sock_should_retry(ret))
				BIO_set_retry_read(b);
			}
		}
	return(ret);
	}
Ejemplo n.º 4
0
static int conn_write(BIO *b, const char *in, int inl)
	{
	int ret;
	BIO_CONNECT *data;

	data=(BIO_CONNECT *)b->ptr;
	if (data->state != BIO_CONN_S_OK)
		{
		ret=conn_state(b,data);
		if (ret <= 0) return(ret);
		}

	clear_socket_error();
	ret=writesocket(b->num,in,inl);
	BIO_clear_retry_flags(b);
	if (ret <= 0)
		{
		if (BIO_sock_should_retry(ret))
			BIO_set_retry_write(b);
		}
	return(ret);
	}
Ejemplo n.º 5
0
static int conn_write(BIO *bio, const char *in, int in_len) {
  int ret;
  BIO_CONNECT *data;

  data = (BIO_CONNECT *)bio->ptr;
  if (data->state != BIO_CONN_S_OK) {
    ret = conn_state(bio, data);
    if (ret <= 0) {
      return ret;
    }
  }

  bio_clear_socket_error();
  ret = send(bio->num, in, in_len, 0);
  BIO_clear_retry_flags(bio);
  if (ret <= 0) {
    if (bio_fd_should_retry(ret)) {
      BIO_set_retry_write(bio);
    }
  }

  return ret;
}
Ejemplo n.º 6
0
static int conn_read(BIO *bio, char *out, int out_len) {
  int ret = 0;
  BIO_CONNECT *data;

  data = (BIO_CONNECT *)bio->ptr;
  if (data->state != BIO_CONN_S_OK) {
    ret = conn_state(bio, data);
    if (ret <= 0) {
      return ret;
    }
  }

  bio_clear_socket_error();
  ret = recv(bio->num, out, out_len, 0);
  BIO_clear_retry_flags(bio);
  if (ret <= 0) {
    if (bio_fd_should_retry(ret)) {
      BIO_set_retry_read(bio);
    }
  }

  return ret;
}
Ejemplo n.º 7
0
static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
  int *ip;
  long ret = 1;
  BIO_CONNECT *data;

  data = (BIO_CONNECT *)bio->ptr;

  switch (cmd) {
    case BIO_CTRL_RESET:
      ret = 0;
      data->state = BIO_CONN_S_BEFORE;
      conn_close_socket(bio);
      bio->flags = 0;
      break;
    case BIO_C_DO_STATE_MACHINE:
      /* use this one to start the connection */
      if (data->state != BIO_CONN_S_OK) {
        ret = (long)conn_state(bio, data);
      } else {
        ret = 1;
      }
      break;
    case BIO_C_SET_CONNECT:
      if (ptr != NULL) {
        bio->init = 1;
        if (num == 0) {
          OPENSSL_free(data->param_hostname);
          data->param_hostname = BUF_strdup(ptr);
          if (data->param_hostname == NULL) {
            ret = 0;
          }
        } else if (num == 1) {
          OPENSSL_free(data->param_port);
          data->param_port = BUF_strdup(ptr);
          if (data->param_port == NULL) {
            ret = 0;
          }
        } else {
          ret = 0;
        }
      }
      break;
    case BIO_C_SET_NBIO:
      data->nbio = (int)num;
      break;
    case BIO_C_GET_FD:
      if (bio->init) {
        ip = (int *)ptr;
        if (ip != NULL) {
          *ip = bio->num;
        }
        ret = bio->num;
      } else {
        ret = -1;
      }
      break;
    case BIO_CTRL_GET_CLOSE:
      ret = bio->shutdown;
      break;
    case BIO_CTRL_SET_CLOSE:
      bio->shutdown = (int)num;
      break;
    case BIO_CTRL_PENDING:
    case BIO_CTRL_WPENDING:
      ret = 0;
      break;
    case BIO_CTRL_FLUSH:
      break;
    case BIO_CTRL_SET_CALLBACK: {
#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
		OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
		ret = -1;
#else
      ret = 0;
#endif
    } break;
    case BIO_CTRL_GET_CALLBACK: {
      int (**fptr)(const BIO *bio, int state, int xret);
      fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
      *fptr = data->info_callback;
    } break;
    default:
      ret = 0;
      break;
  }
  return (ret);
}
Ejemplo n.º 8
0
/*
 * []----
 * | sess_process -- handle messages from the connection(s)
 * []----
 */
static void *
sess_process(void *v)
{
	iscsi_sess_t	*s = (iscsi_sess_t *)v;
	iscsi_conn_t	*c;
	iscsi_cmd_t	*cmd;
	msg_t		*m;
	Boolean_t	process = True;
	mgmt_request_t	*mgmt;
	name_request_t	*nr;
	t10_cmd_t	*t10_cmd;
	char		**buf,
			local_buf[16];
	int		lun;
	extern void dataout_callback(t10_cmd_t *t, char *data, size_t *xfer);

	(void) pthread_mutex_lock(&s->s_mutex);
	s->s_state = SS_RUNNING;
	(void) pthread_mutex_unlock(&s->s_mutex);
	do {
		m = queue_message_get(s->s_sessq);
		switch (m->msg_type) {
		case msg_cmd_send:
			cmd = (iscsi_cmd_t *)m->msg_data;
			if (s->s_t10 == NULL) {

				/*
				 * The value of 0x960 comes from T10.
				 * See SPC-4, revision 1a, section 6.4.2,
				 * table 87
				 *
				 * XXX Need to rethink how I should do
				 * the callback.
				 */
				s->s_t10 = t10_handle_create(s->s_t_name,
				    T10_TRANS_ISCSI, s->s_conn_head->c_tpgt,
				    s->s_conn_head->c_max_burst_len,
				    s->s_t10q, dataout_callback);
			}
			if (t10_cmd_create(s->s_t10, cmd->c_lun, cmd->c_scb,
			    cmd->c_scb_len, (transport_t)cmd,
			    &t10_cmd) == False) {

				queue_prt(s->s_mgmtq, Q_SESS_ERRS,
				    "SES%x  FAILED to create cmd", s->s_num);
				/*
				 * If the command create failed, the T10 layer
				 * will attempt to create a sense buffer
				 * telling the initiator what went wrong. If
				 * that layer was unable to accomplish that
				 * things are really bad and we need to just
				 * close the connection.
				 */
				if (cmd->c_t10_cmd != NULL) {
					queue_message_set(
					    cmd->c_allegiance->c_dataq,
					    0, msg_cmd_cmplt, t10_cmd);
				} else
					conn_state(cmd->c_allegiance, T11);
			} else {
				(void) pthread_mutex_lock(
				    &cmd->c_allegiance->c_mutex);
				if (cmd->c_state != CmdCanceled) {
					cmd->c_t10_cmd = t10_cmd;
					(void) t10_cmd_send(s->s_t10,
					    cmd->c_t10_cmd, cmd->c_data,
					    cmd->c_data_len);
				} else {
					t10_cmd_state(t10_cmd,
					    T10_Cmd_Event_Canceled);
				}
				(void) pthread_mutex_unlock(
				    &cmd->c_allegiance->c_mutex);
			}
			break;

		case msg_cmd_data_out:
			cmd = (iscsi_cmd_t *)m->msg_data;
			if (s->s_t10 != NULL)
				(void) t10_cmd_data(s->s_t10, cmd->c_t10_cmd,
				    cmd->c_offset_out, cmd->c_data,
				    cmd->c_data_len);
			break;

		case msg_targ_inventory_change:
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, InventoryChange,
				    0, 0);
			break;

		case msg_lu_capacity_change:
			lun = (int)(uintptr_t)m->msg_data;
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, CapacityChange,
				    lun, 0);
			break;

		case msg_reset_targ:
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, ResetTarget,
				    0, 0);
			break;

		case msg_reset_lu:
			if (s->s_t10 != NULL)
				(void) t10_task_mgmt(s->s_t10, ResetLun,
				    (int)(uintptr_t)m->msg_data, 0);
			break;

		case msg_shutdown:
			(void) pthread_mutex_lock(&s->s_mutex);
			s->s_state = SS_SHUTDOWN_START;
			(void) pthread_mutex_unlock(&s->s_mutex);

			/*
			 * Shutdown rquest comming from a connection. Only
			 * shutdown the STE if this is the last connection
			 * for this session.
			 */
			c = (iscsi_conn_t *)m->msg_data;
			if (session_remove_connection(s, c) == True) {
				queue_prt(s->s_mgmtq, Q_SESS_NONIO,
				    "SES%x  Starting shutdown", s->s_num);

				/*
				 * If this is the last connection for this
				 * session send a message to the SAM-3 layer to
				 * shutdown.
				 */
				if (s->s_t10 != NULL) {
					t10_handle_disable(s->s_t10);
				}
				queue_message_set(s->s_t10q, 0,
				    msg_shutdown_rsp, 0);
				process = False;
			} else {

				/*
				 * Since this isn't the last connection for
				 * the session, acknowledge the connection
				 * request now since it's references from
				 * this session have been removed.
				 */
				queue_message_set(c->c_dataq, 0,
				    msg_shutdown_rsp, (void *)False);
			}
			break;

		case msg_initiator_name:
			nr = (name_request_t *)m->msg_data;
			s->s_i_name = strdup(nr->nr_name);

			/*
			 * Acknowledge the request by sending back an empty
			 * message.
			 */
			queue_message_set(nr->nr_q, 0, msg_initiator_name, 0);
			break;

		case msg_initiator_alias:
			nr = (name_request_t *)m->msg_data;
			s->s_i_alias = strdup(nr->nr_name);

			/*
			 * Acknowledge the request by sending back an empty
			 * message.
			 */
			queue_message_set(nr->nr_q, 0, msg_initiator_alias, 0);
			break;

		case msg_target_name:
			nr = (name_request_t *)m->msg_data;
			s->s_t_name = strdup(nr->nr_name);

			/*
			 * Acknowledge the request by sending back an empty
			 * message.
			 */
			queue_message_set(nr->nr_q, 0, msg_target_name, 0);
			break;

		case msg_mgmt_rqst:
			mgmt		= (mgmt_request_t *)m->msg_data;
			m->msg_data	= NULL;

			(void) pthread_mutex_lock(&mgmt->m_resp_mutex);
			buf = mgmt->m_u.m_resp;

			if ((s->s_type == SessionNormal) &&
			    (mgmt->m_request == mgmt_full_phase_statistics) &&
			    (strcmp(s->s_t_name, mgmt->m_targ_name) == 0)) {

				buf_add_tag(buf, XML_ELEMENT_CONN, Tag_Start);
				buf_add_tag(buf, s->s_i_name, Tag_String);
				if (s->s_i_alias != NULL) {
					xml_add_tag(buf, XML_ELEMENT_ALIAS,
					    s->s_i_alias);
				}

				/*
				 * Need to loop through the connections
				 * and create one time_connected tag for
				 * each. This will be needed once MC/S support
				 * is added.
				 */
				(void) snprintf(local_buf, sizeof (local_buf),
				    "%d",
				    mgmt->m_time - s->s_conn_head->c_up_at);
				xml_add_tag(buf, XML_ELEMENT_TIMECON,
				    local_buf);

				buf_add_tag(buf, XML_ELEMENT_STATS, Tag_Start);

				t10_targ_stat(s->s_t10, buf);

				buf_add_tag(buf, XML_ELEMENT_STATS, Tag_End);
				buf_add_tag(buf, XML_ELEMENT_CONN, Tag_End);
			}

			(void) pthread_mutex_unlock(&mgmt->m_resp_mutex);

			queue_message_set(mgmt->m_q, 0, msg_mgmt_rply, 0);

			break;

		default:
			queue_prt(s->s_mgmtq, Q_SESS_ERRS,
			    "SES%x  Unknown msg type (%d) from Connection",
			    s->s_num, m->msg_type);
			break;
		}
		queue_message_free(m);
	} while (process == True);

	return (NULL);
}
Ejemplo n.º 9
0
static long conn_ctrl(BIO *b, int cmd, long num, void *ptr)
	{
	BIO *dbio;
	int *ip;
	const char **pptr;
	long ret=1;
	BIO_CONNECT *data;

	data=(BIO_CONNECT *)b->ptr;

	switch (cmd)
		{
	case BIO_CTRL_RESET:
		ret=0;
		data->state=BIO_CONN_S_BEFORE;
		conn_close_socket(b);
		b->flags=0;
		break;
	case BIO_C_DO_STATE_MACHINE:
		/* use this one to start the connection */
		if (!data->state != BIO_CONN_S_OK)
			ret=(long)conn_state(b,data);
		else
			ret=1;
		break;
	case BIO_C_GET_CONNECT:
		if (ptr != NULL)
			{
			pptr=(const char **)ptr;
			if (num == 0)
				{
				*pptr=data->param_hostname;

				}
			else if (num == 1)
				{
				*pptr=data->param_port;
				}
			else if (num == 2)
				{
				*pptr= (char *)&(data->ip[0]);
				}
			else if (num == 3)
				{
				*((int *)ptr)=data->port;
				}
			if ((!b->init) || (ptr == NULL))
				*pptr="not initialized";
			ret=1;
			}
		break;
	case BIO_C_SET_CONNECT:
		if (ptr != NULL)
			{
			b->init=1;
			if (num == 0)
				{
				if (data->param_hostname != NULL)
					OPENSSL_free(data->param_hostname);
				data->param_hostname=BUF_strdup(ptr);
				}
			else if (num == 1)
				{
				if (data->param_port != NULL)
					OPENSSL_free(data->param_port);
				data->param_port=BUF_strdup(ptr);
				}
			else if (num == 2)
				{
				char buf[16];
				unsigned char *p = ptr;

				BIO_snprintf(buf,sizeof buf,"%d.%d.%d.%d",
					     p[0],p[1],p[2],p[3]);
				if (data->param_hostname != NULL)
					OPENSSL_free(data->param_hostname);
				data->param_hostname=BUF_strdup(buf);
				memcpy(&(data->ip[0]),ptr,4);
				}
			else if (num == 3)
				{
				char buf[DECIMAL_SIZE(int)+1];

				BIO_snprintf(buf,sizeof buf,"%d",*(int *)ptr);
				if (data->param_port != NULL)
					OPENSSL_free(data->param_port);
				data->param_port=BUF_strdup(buf);
				data->port= *(int *)ptr;
				}
			}
		break;
	case BIO_C_SET_NBIO:
		data->nbio=(int)num;
		break;
	case BIO_C_GET_FD:
		if (b->init)
			{
			ip=(int *)ptr;
			if (ip != NULL)
				*ip=b->num;
			ret=b->num;
			}
		else
			ret= -1;
		break;
	case BIO_CTRL_GET_CLOSE:
		ret=b->shutdown;
		break;
	case BIO_CTRL_SET_CLOSE:
		b->shutdown=(int)num;
		break;
	case BIO_CTRL_PENDING:
	case BIO_CTRL_WPENDING:
		ret=0;
		break;
	case BIO_CTRL_FLUSH:
		break;
	case BIO_CTRL_DUP:
		{
		dbio=(BIO *)ptr;
		if (data->param_port)
			BIO_set_conn_port(dbio,data->param_port);
		if (data->param_hostname)
			BIO_set_conn_hostname(dbio,data->param_hostname);
		BIO_set_nbio(dbio,data->nbio);
		/* FIXME: the cast of the function seems unlikely to be a good idea */
                (void)BIO_set_info_callback(dbio,(bio_info_cb *)data->info_callback);
		}
		break;
	case BIO_CTRL_SET_CALLBACK:
		{
#if 0 /* FIXME: Should this be used?  -- Richard Levitte */
		BIOerr(BIO_F_CONN_CTRL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
		ret = -1;
#else
		ret=0;
#endif
		}
		break;
	case BIO_CTRL_GET_CALLBACK:
		{
		int (**fptr)();

		fptr=(int (**)())ptr;
		*fptr=data->info_callback;
		}
		break;
	default:
		ret=0;
		break;
		}
	return(ret);
	}