xref: /openbsd-src/usr.sbin/iscsid/session.c (revision 7b8339380a5a5ef7c0e48ec10c485217e37b358f)
1*7b833938Sclaudio /*	$OpenBSD: session.c,v 1.13 2025/01/22 16:06:36 claudio Exp $ */
236af5452Sclaudio 
336af5452Sclaudio /*
436af5452Sclaudio  * Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
536af5452Sclaudio  *
636af5452Sclaudio  * Permission to use, copy, modify, and distribute this software for any
736af5452Sclaudio  * purpose with or without fee is hereby granted, provided that the above
836af5452Sclaudio  * copyright notice and this permission notice appear in all copies.
936af5452Sclaudio  *
1036af5452Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1136af5452Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1236af5452Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1336af5452Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1436af5452Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1536af5452Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1636af5452Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1736af5452Sclaudio  */
1836af5452Sclaudio 
1936af5452Sclaudio #include <sys/types.h>
2012bd4d7fSclaudio #include <sys/ioctl.h>
2136af5452Sclaudio #include <sys/queue.h>
2236af5452Sclaudio #include <sys/socket.h>
2336af5452Sclaudio #include <sys/uio.h>
2436af5452Sclaudio 
2536af5452Sclaudio #include <scsi/iscsi.h>
2612bd4d7fSclaudio #include <scsi/scsi_all.h>
2712bd4d7fSclaudio #include <dev/vscsivar.h>
2836af5452Sclaudio 
2936af5452Sclaudio #include <event.h>
3036af5452Sclaudio #include <stdio.h>
3136af5452Sclaudio #include <stdlib.h>
3236af5452Sclaudio #include <string.h>
3336af5452Sclaudio #include <unistd.h>
3436af5452Sclaudio 
3536af5452Sclaudio #include "iscsid.h"
3636af5452Sclaudio #include "log.h"
3736af5452Sclaudio 
38cb408c6cSclaudio int	sess_do_start(struct session *, struct sessev *);
3912bd4d7fSclaudio int	sess_do_conn_loggedin(struct session *, struct sessev *);
4012bd4d7fSclaudio int	sess_do_conn_fail(struct session *, struct sessev *);
4112bd4d7fSclaudio int	sess_do_conn_closed(struct session *, struct sessev *);
42daed3c83Sclaudio int	sess_do_stop(struct session *, struct sessev *);
43daed3c83Sclaudio int	sess_do_free(struct session *, struct sessev *);
44daed3c83Sclaudio int	sess_do_reinstatement(struct session *, struct sessev *);
45cb408c6cSclaudio 
46cb408c6cSclaudio const char *sess_state(int);
47cb408c6cSclaudio const char *sess_event(enum s_event);
48cb408c6cSclaudio 
4936af5452Sclaudio void
50cb408c6cSclaudio session_cleanup(struct session *s)
5136af5452Sclaudio {
5236af5452Sclaudio 	struct connection *c;
5336af5452Sclaudio 
5412bd4d7fSclaudio 	taskq_cleanup(&s->tasks);
5512bd4d7fSclaudio 
5636af5452Sclaudio 	while ((c = TAILQ_FIRST(&s->connections)) != NULL)
5736af5452Sclaudio 		conn_free(c);
5836af5452Sclaudio 
5936af5452Sclaudio 	free(s->config.TargetName);
6036af5452Sclaudio 	free(s->config.InitiatorName);
6136af5452Sclaudio 	free(s);
6236af5452Sclaudio }
6336af5452Sclaudio 
6412bd4d7fSclaudio int
6512bd4d7fSclaudio session_shutdown(struct session *s)
6612bd4d7fSclaudio {
6712bd4d7fSclaudio 	log_debug("session[%s] going down", s->config.SessionName);
6812bd4d7fSclaudio 
6912bd4d7fSclaudio 	s->action = SESS_ACT_DOWN;
70daed3c83Sclaudio 	if (s->state & (SESS_INIT | SESS_FREE)) {
71daed3c83Sclaudio 		/* no active session, so do a quick cleanup */
7212bd4d7fSclaudio 		struct connection *c;
7312bd4d7fSclaudio 		while ((c = TAILQ_FIRST(&s->connections)) != NULL)
7412bd4d7fSclaudio 			conn_free(c);
7512bd4d7fSclaudio 		return 0;
7612bd4d7fSclaudio 	}
7712bd4d7fSclaudio 
7812bd4d7fSclaudio 	/* cleanup task queue and issue a logout */
7912bd4d7fSclaudio 	taskq_cleanup(&s->tasks);
8012bd4d7fSclaudio 	initiator_logout(s, NULL, ISCSI_LOGOUT_CLOSE_SESS);
8112bd4d7fSclaudio 
8212bd4d7fSclaudio 	return 1;
8312bd4d7fSclaudio }
8412bd4d7fSclaudio 
8536af5452Sclaudio void
8636af5452Sclaudio session_config(struct session *s, struct session_config *sc)
8736af5452Sclaudio {
8836af5452Sclaudio 	free(s->config.TargetName);
8936af5452Sclaudio 	s->config.TargetName = NULL;
9036af5452Sclaudio 	free(s->config.InitiatorName);
9136af5452Sclaudio 	s->config.InitiatorName = NULL;
9236af5452Sclaudio 
9336af5452Sclaudio 	s->config = *sc;
9436af5452Sclaudio 
9536af5452Sclaudio 	if (sc->TargetName) {
9636af5452Sclaudio 		s->config.TargetName = strdup(sc->TargetName);
9736af5452Sclaudio 		if (s->config.TargetName == NULL)
9836af5452Sclaudio 			fatal("strdup");
9936af5452Sclaudio 	}
10036af5452Sclaudio 	if (sc->InitiatorName) {
10136af5452Sclaudio 		s->config.InitiatorName = strdup(sc->InitiatorName);
10236af5452Sclaudio 		if (s->config.InitiatorName == NULL)
10336af5452Sclaudio 			fatal("strdup");
10436af5452Sclaudio 	} else
10536af5452Sclaudio 		s->config.InitiatorName = default_initiator_name();
10636af5452Sclaudio }
10736af5452Sclaudio 
10836af5452Sclaudio void
10936af5452Sclaudio session_task_issue(struct session *s, struct task *t)
11036af5452Sclaudio {
11136af5452Sclaudio 	TAILQ_INSERT_TAIL(&s->tasks, t, entry);
11236af5452Sclaudio 	session_schedule(s);
11336af5452Sclaudio }
11436af5452Sclaudio 
11536af5452Sclaudio void
11612bd4d7fSclaudio session_logout_issue(struct session *s, struct task *t)
11712bd4d7fSclaudio {
11812bd4d7fSclaudio 	struct connection *c, *rc = NULL;
11912bd4d7fSclaudio 
12012bd4d7fSclaudio 	/* find first free session or first available session */
12112bd4d7fSclaudio 	TAILQ_FOREACH(c, &s->connections, entry) {
12212bd4d7fSclaudio 		if (conn_task_ready(c)) {
12312bd4d7fSclaudio 			conn_fsm(c, CONN_EV_LOGOUT);
12412bd4d7fSclaudio 			conn_task_issue(c, t);
12512bd4d7fSclaudio 			return;
12612bd4d7fSclaudio 		}
12712bd4d7fSclaudio 		if (c->state & CONN_RUNNING)
12812bd4d7fSclaudio 			rc = c;
12912bd4d7fSclaudio 	}
13012bd4d7fSclaudio 
13112bd4d7fSclaudio 	if (rc) {
13212bd4d7fSclaudio 		conn_fsm(rc, CONN_EV_LOGOUT);
13312bd4d7fSclaudio 		conn_task_issue(rc, t);
13412bd4d7fSclaudio 		return;
13512bd4d7fSclaudio 	}
13612bd4d7fSclaudio 
13712bd4d7fSclaudio 	/* XXX must open new connection, gulp */
13812bd4d7fSclaudio 	fatalx("session_logout_issue needs more work");
13912bd4d7fSclaudio }
14012bd4d7fSclaudio 
14112bd4d7fSclaudio void
14236af5452Sclaudio session_schedule(struct session *s)
14336af5452Sclaudio {
14436af5452Sclaudio 	struct task *t = TAILQ_FIRST(&s->tasks);
14536af5452Sclaudio 	struct connection *c;
14636af5452Sclaudio 
14736af5452Sclaudio 	if (!t)
14836af5452Sclaudio 		return;
14936af5452Sclaudio 
15036af5452Sclaudio 	/* XXX IMMEDIATE TASK NEED SPECIAL HANDLING !!!! */
15136af5452Sclaudio 
15236af5452Sclaudio 	/* wake up a idle connection or a not busy one */
15336af5452Sclaudio 	/* XXX this needs more work as it makes the daemon go wrooOOOMM */
15436af5452Sclaudio 	TAILQ_FOREACH(c, &s->connections, entry)
155cb408c6cSclaudio 		if (conn_task_ready(c)) {
156cb408c6cSclaudio 			TAILQ_REMOVE(&s->tasks, t, entry);
157cb408c6cSclaudio 			conn_task_issue(c, t);
15836af5452Sclaudio 			return;
159cb408c6cSclaudio 		}
160cb408c6cSclaudio }
161cb408c6cSclaudio 
162cb408c6cSclaudio /*
163cb408c6cSclaudio  * The session FSM runs from a callback so that the connection FSM can finish.
164cb408c6cSclaudio  */
165cb408c6cSclaudio void
1660908bd10Sclaudio session_fsm(struct sessev *sev, enum s_event event, unsigned int timeout)
167cb408c6cSclaudio {
1680908bd10Sclaudio 	struct session *s = sev->sess;
169cb408c6cSclaudio 	struct timeval tv;
170cb408c6cSclaudio 
171daed3c83Sclaudio 	log_debug("session_fsm[%s]: %s ev %s timeout %d",
172daed3c83Sclaudio 	    s->config.SessionName, sess_state(s->state),
1730908bd10Sclaudio 	    sess_event(event), timeout);
174daed3c83Sclaudio 
1750908bd10Sclaudio 	sev->event = event;
176cb408c6cSclaudio 
177cb408c6cSclaudio 	timerclear(&tv);
178daed3c83Sclaudio 	tv.tv_sec = timeout;
1790908bd10Sclaudio 	if (evtimer_add(&sev->ev, &tv) == -1)
180cb408c6cSclaudio 		fatal("session_fsm");
181cb408c6cSclaudio }
182cb408c6cSclaudio 
183cb408c6cSclaudio struct {
184cb408c6cSclaudio 	int		state;
185cb408c6cSclaudio 	enum s_event	event;
186cb408c6cSclaudio 	int		(*action)(struct session *, struct sessev *);
187cb408c6cSclaudio } s_fsm[] = {
188cb408c6cSclaudio 	{ SESS_INIT, SESS_EV_START, sess_do_start },
189daed3c83Sclaudio 	{ SESS_FREE, SESS_EV_START, sess_do_start },
190daed3c83Sclaudio 	{ SESS_FREE, SESS_EV_CONN_LOGGED_IN, sess_do_conn_loggedin },	/* N1 */
191daed3c83Sclaudio 	{ SESS_FREE, SESS_EV_CLOSED, sess_do_stop },
19212bd4d7fSclaudio 	{ SESS_LOGGED_IN, SESS_EV_CONN_LOGGED_IN, sess_do_conn_loggedin },
193daed3c83Sclaudio 	{ SESS_RUNNING, SESS_EV_CONN_CLOSED, sess_do_conn_closed },	/* N3 */
194daed3c83Sclaudio 	{ SESS_RUNNING, SESS_EV_CONN_FAIL, sess_do_conn_fail },		/* N5 */
195daed3c83Sclaudio 	{ SESS_RUNNING, SESS_EV_CLOSED, sess_do_free },		/* XXX */
196daed3c83Sclaudio 	{ SESS_FAILED, SESS_EV_START, sess_do_start },
197daed3c83Sclaudio 	{ SESS_FAILED, SESS_EV_TIMEOUT, sess_do_free },			/* N6 */
198daed3c83Sclaudio 	{ SESS_FAILED, SESS_EV_FREE, sess_do_free },			/* N6 */
199daed3c83Sclaudio 	{ SESS_FAILED, SESS_EV_CONN_LOGGED_IN, sess_do_reinstatement },	/* N4 */
200cb408c6cSclaudio 	{ 0, 0, NULL }
201cb408c6cSclaudio };
202cb408c6cSclaudio 
203cb408c6cSclaudio void
204cb408c6cSclaudio session_fsm_callback(int fd, short event, void *arg)
205cb408c6cSclaudio {
206daed3c83Sclaudio 	struct sessev *sev = arg;
207daed3c83Sclaudio 	struct session *s = sev->sess;
208cb408c6cSclaudio 	int	i, ns;
209cb408c6cSclaudio 
210cb408c6cSclaudio 	for (i = 0; s_fsm[i].action != NULL; i++) {
211cb408c6cSclaudio 		if (s->state & s_fsm[i].state &&
212cb408c6cSclaudio 		    sev->event == s_fsm[i].event) {
213cb408c6cSclaudio 			log_debug("sess_fsm[%s]: %s ev %s",
214cb408c6cSclaudio 			    s->config.SessionName, sess_state(s->state),
215cb408c6cSclaudio 			    sess_event(sev->event));
216cb408c6cSclaudio 			ns = s_fsm[i].action(s, sev);
217cb408c6cSclaudio 			if (ns == -1)
218cb408c6cSclaudio 				/* XXX better please */
219cb408c6cSclaudio 				fatalx("sess_fsm: action failed");
220cb408c6cSclaudio 			log_debug("sess_fsm[%s]: new state %s",
221cb408c6cSclaudio 			    s->config.SessionName,
222cb408c6cSclaudio 			    sess_state(ns));
223cb408c6cSclaudio 			s->state = ns;
224cb408c6cSclaudio 			break;
225cb408c6cSclaudio 		}
226cb408c6cSclaudio 	}
227cb408c6cSclaudio 	if (s_fsm[i].action == NULL) {
228cb408c6cSclaudio 		log_warnx("sess_fsm[%s]: unhandled state transition "
229cb408c6cSclaudio 		    "[%s, %s]", s->config.SessionName,
230cb408c6cSclaudio 		    sess_state(s->state), sess_event(sev->event));
231cb408c6cSclaudio 		fatalx("bjork bjork bjork");
232cb408c6cSclaudio 	}
233cb408c6cSclaudio }
234cb408c6cSclaudio 
235cb408c6cSclaudio int
236cb408c6cSclaudio sess_do_start(struct session *s, struct sessev *sev)
237cb408c6cSclaudio {
238cb408c6cSclaudio 	log_debug("new connection to %s",
239cb408c6cSclaudio 	    log_sockaddr(&s->config.connection.TargetAddr));
2400933eeb9Sclaudio 
241aeec9c16Sclaudio 	/* initialize the session params, and reset the active state */
2420933eeb9Sclaudio 	s->mine = initiator_sess_defaults;
2430933eeb9Sclaudio 	s->his = iscsi_sess_defaults;
2440933eeb9Sclaudio 	s->active = iscsi_sess_defaults;
2450933eeb9Sclaudio 
246daed3c83Sclaudio 	if (s->config.SessionType != SESSION_TYPE_DISCOVERY &&
247daed3c83Sclaudio 	    s->config.MaxConnections)
2480933eeb9Sclaudio 		s->mine.MaxConnections = s->config.MaxConnections;
2490933eeb9Sclaudio 
250cb408c6cSclaudio 	conn_new(s, &s->config.connection);
251cb408c6cSclaudio 
252daed3c83Sclaudio 	/* XXX kill SESS_FREE it seems to be bad */
253daed3c83Sclaudio 	if (s->state == SESS_INIT)
25412bd4d7fSclaudio 		return SESS_FREE;
255daed3c83Sclaudio 	else
256daed3c83Sclaudio 		return s->state;
257cb408c6cSclaudio }
258cb408c6cSclaudio 
259cb408c6cSclaudio int
26012bd4d7fSclaudio sess_do_conn_loggedin(struct session *s, struct sessev *sev)
261cb408c6cSclaudio {
26212bd4d7fSclaudio 	if (s->state & SESS_LOGGED_IN)
26312bd4d7fSclaudio 		return SESS_LOGGED_IN;
26412bd4d7fSclaudio 
2657bc8b37fSclaudio 	if (s->config.SessionType == SESSION_TYPE_DISCOVERY) {
26612bd4d7fSclaudio 		initiator_discovery(s);
2677bc8b37fSclaudio 		return SESS_LOGGED_IN;
2687bc8b37fSclaudio 	}
2697bc8b37fSclaudio 
2707bc8b37fSclaudio 	iscsi_merge_sess_params(&s->active, &s->mine, &s->his);
27112bd4d7fSclaudio 	vscsi_event(VSCSI_REQPROBE, s->target, -1);
272daed3c83Sclaudio 	s->holdTimer = 0;
27312bd4d7fSclaudio 
27412bd4d7fSclaudio 	return SESS_LOGGED_IN;
27512bd4d7fSclaudio }
27612bd4d7fSclaudio 
27712bd4d7fSclaudio int
27812bd4d7fSclaudio sess_do_conn_fail(struct session *s, struct sessev *sev)
27912bd4d7fSclaudio {
28012bd4d7fSclaudio 	struct connection *c = sev->conn;
28112bd4d7fSclaudio 	int state = SESS_FREE;
28212bd4d7fSclaudio 
28312bd4d7fSclaudio 	if (sev->conn == NULL) {
28412bd4d7fSclaudio 		log_warnx("Just what do you think you're doing, Dave?");
28512bd4d7fSclaudio 		return -1;
28612bd4d7fSclaudio 	}
28712bd4d7fSclaudio 
288cb408c6cSclaudio 	/*
289cb408c6cSclaudio 	 * cleanup connections:
290cb408c6cSclaudio 	 * Connections in state FREE can be removed.
291cb408c6cSclaudio 	 * Connections in any error state will cause the session to enter
292cb408c6cSclaudio 	 * the FAILED state. If no sessions are left and the session was
293daed3c83Sclaudio 	 * not already FREE then implicit recovery needs to be done.
294cb408c6cSclaudio 	 */
29512bd4d7fSclaudio 
29612bd4d7fSclaudio 	switch (c->state) {
29712bd4d7fSclaudio 	case CONN_FREE:
29812bd4d7fSclaudio 		conn_free(c);
29912bd4d7fSclaudio 		break;
30012bd4d7fSclaudio 	case CONN_CLEANUP_WAIT:
30112bd4d7fSclaudio 		break;
30212bd4d7fSclaudio 	default:
30312bd4d7fSclaudio 		log_warnx("It can only be attributable to human error.");
30412bd4d7fSclaudio 		return -1;
30512bd4d7fSclaudio 	}
30612bd4d7fSclaudio 
30712bd4d7fSclaudio 	TAILQ_FOREACH(c, &s->connections, entry) {
30812bd4d7fSclaudio 		if (c->state & CONN_FAILED) {
30912bd4d7fSclaudio 			state = SESS_FAILED;
310daed3c83Sclaudio 			conn_fsm(c, CONN_EV_CLEANING_UP);
311daed3c83Sclaudio 		} else if (c->state & CONN_RUNNING && state != SESS_FAILED)
31212bd4d7fSclaudio 			state = SESS_LOGGED_IN;
31312bd4d7fSclaudio 	}
31412bd4d7fSclaudio 
3150908bd10Sclaudio 	session_fsm(&s->sev, SESS_EV_START, s->holdTimer);
316daed3c83Sclaudio 	/* exponential back-off on constant failure */
317daed3c83Sclaudio 	if (s->holdTimer < ISCSID_HOLD_TIME_MAX)
318daed3c83Sclaudio 		s->holdTimer = s->holdTimer ? s->holdTimer * 2 : 1;
319daed3c83Sclaudio 
32012bd4d7fSclaudio 	return state;
32112bd4d7fSclaudio }
32212bd4d7fSclaudio 
32312bd4d7fSclaudio int
32412bd4d7fSclaudio sess_do_conn_closed(struct session *s, struct sessev *sev)
32512bd4d7fSclaudio {
32612bd4d7fSclaudio 	struct connection *c = sev->conn;
32712bd4d7fSclaudio 	int state = SESS_FREE;
32812bd4d7fSclaudio 
32912bd4d7fSclaudio 	if (c == NULL || c->state != CONN_FREE) {
33012bd4d7fSclaudio 		log_warnx("Just what do you think you're doing, Dave?");
33112bd4d7fSclaudio 		return -1;
33212bd4d7fSclaudio 	}
33312bd4d7fSclaudio 	conn_free(c);
33412bd4d7fSclaudio 
33512bd4d7fSclaudio 	TAILQ_FOREACH(c, &s->connections, entry) {
33612bd4d7fSclaudio 		if (c->state & CONN_FAILED) {
33712bd4d7fSclaudio 			state = SESS_FAILED;
33812bd4d7fSclaudio 			break;
33912bd4d7fSclaudio 		} else if (c->state & CONN_RUNNING)
34012bd4d7fSclaudio 			state = SESS_LOGGED_IN;
34112bd4d7fSclaudio 	}
34212bd4d7fSclaudio 
34312bd4d7fSclaudio 	return state;
34412bd4d7fSclaudio }
34512bd4d7fSclaudio 
34612bd4d7fSclaudio int
347daed3c83Sclaudio sess_do_stop(struct session *s, struct sessev *sev)
348daed3c83Sclaudio {
349daed3c83Sclaudio 	struct connection *c;
350daed3c83Sclaudio 
351daed3c83Sclaudio 	/* XXX do graceful closing of session and go to INIT state at the end */
352daed3c83Sclaudio 
353daed3c83Sclaudio 	while ((c = TAILQ_FIRST(&s->connections)) != NULL)
354daed3c83Sclaudio 		conn_free(c);
355daed3c83Sclaudio 
356daed3c83Sclaudio 	/* XXX anything else to reset to initial state? */
357daed3c83Sclaudio 	return SESS_INIT;
358daed3c83Sclaudio }
359daed3c83Sclaudio 
360daed3c83Sclaudio int
361daed3c83Sclaudio sess_do_free(struct session *s, struct sessev *sev)
36212bd4d7fSclaudio {
36312bd4d7fSclaudio 	struct connection *c;
36412bd4d7fSclaudio 
36512bd4d7fSclaudio 	while ((c = TAILQ_FIRST(&s->connections)) != NULL)
36612bd4d7fSclaudio 		conn_free(c);
36712bd4d7fSclaudio 
368daed3c83Sclaudio 	return SESS_FREE;
369daed3c83Sclaudio }
37012bd4d7fSclaudio 
371daed3c83Sclaudio const char *conn_state(int);
372daed3c83Sclaudio 
373daed3c83Sclaudio 
374daed3c83Sclaudio int
375daed3c83Sclaudio sess_do_reinstatement(struct session *s, struct sessev *sev)
376daed3c83Sclaudio {
377daed3c83Sclaudio 	struct connection *c, *nc;
378daed3c83Sclaudio 
379daed3c83Sclaudio 	TAILQ_FOREACH_SAFE(c, &s->connections, entry, nc) {
380daed3c83Sclaudio 		log_debug("sess reinstatement[%s]: %s",
381daed3c83Sclaudio 		    s->config.SessionName, conn_state(c->state));
382daed3c83Sclaudio 
383daed3c83Sclaudio 		if (c->state & CONN_FAILED) {
384daed3c83Sclaudio 			conn_fsm(c, CONN_EV_FREE);
385daed3c83Sclaudio 			conn_free(c);
386daed3c83Sclaudio 		}
387daed3c83Sclaudio 	}
388daed3c83Sclaudio 
389daed3c83Sclaudio 	return SESS_LOGGED_IN;
390cb408c6cSclaudio }
391cb408c6cSclaudio 
392cb408c6cSclaudio const char *
393cb408c6cSclaudio sess_state(int s)
394cb408c6cSclaudio {
395cb408c6cSclaudio 	static char buf[15];
396cb408c6cSclaudio 
397cb408c6cSclaudio 	switch (s) {
398cb408c6cSclaudio 	case SESS_INIT:
399cb408c6cSclaudio 		return "INIT";
400cb408c6cSclaudio 	case SESS_FREE:
401cb408c6cSclaudio 		return "FREE";
402cb408c6cSclaudio 	case SESS_LOGGED_IN:
403cb408c6cSclaudio 		return "LOGGED_IN";
404cb408c6cSclaudio 	case SESS_FAILED:
405cb408c6cSclaudio 		return "FAILED";
406cb408c6cSclaudio 	default:
407cb408c6cSclaudio 		snprintf(buf, sizeof(buf), "UKNWN %x", s);
408cb408c6cSclaudio 		return buf;
409cb408c6cSclaudio 	}
410cb408c6cSclaudio 	/* NOTREACHED */
411cb408c6cSclaudio }
412cb408c6cSclaudio 
413cb408c6cSclaudio const char *
414cb408c6cSclaudio sess_event(enum s_event e)
415cb408c6cSclaudio {
416cb408c6cSclaudio 	static char buf[15];
417cb408c6cSclaudio 
418cb408c6cSclaudio 	switch (e) {
419cb408c6cSclaudio 	case SESS_EV_START:
420cb408c6cSclaudio 		return "start";
421daed3c83Sclaudio 	case SESS_EV_STOP:
422daed3c83Sclaudio 		return "stop";
42312bd4d7fSclaudio 	case SESS_EV_CONN_LOGGED_IN:
42412bd4d7fSclaudio 		return "connection logged in";
425cb408c6cSclaudio 	case SESS_EV_CONN_FAIL:
426cb408c6cSclaudio 		return "connection fail";
427cb408c6cSclaudio 	case SESS_EV_CONN_CLOSED:
428cb408c6cSclaudio 		return "connection closed";
429daed3c83Sclaudio 	case SESS_EV_REINSTATEMENT:
430daed3c83Sclaudio 		return "connection reinstated";
43112bd4d7fSclaudio 	case SESS_EV_CLOSED:
43212bd4d7fSclaudio 		return "session closed";
433daed3c83Sclaudio 	case SESS_EV_TIMEOUT:
434daed3c83Sclaudio 		return "timeout";
435daed3c83Sclaudio 	case SESS_EV_FREE:
436daed3c83Sclaudio 		return "free";
437cb408c6cSclaudio 	case SESS_EV_FAIL:
438cb408c6cSclaudio 		return "fail";
439cb408c6cSclaudio 	}
440cb408c6cSclaudio 
441cb408c6cSclaudio 	snprintf(buf, sizeof(buf), "UKNWN %d", e);
442cb408c6cSclaudio 	return buf;
44336af5452Sclaudio }
444