xref: /dflybsd-src/sbin/iscontrol/fsm.c (revision d50f9ae3448247db98eb135b85b2a32e6e4187f4)
1e25c779eSMatthew Dillon /*-
2e25c779eSMatthew Dillon  * Copyright (c) 2005-2008 Daniel Braniss <danny@cs.huji.ac.il>
3e25c779eSMatthew Dillon  * All rights reserved.
4e25c779eSMatthew Dillon  *
5e25c779eSMatthew Dillon  * Redistribution and use in source and binary forms, with or without
6e25c779eSMatthew Dillon  * modification, are permitted provided that the following conditions
7e25c779eSMatthew Dillon  * are met:
8e25c779eSMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
9e25c779eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
10e25c779eSMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
11e25c779eSMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
12e25c779eSMatthew Dillon  *    documentation and/or other materials provided with the distribution.
13e25c779eSMatthew Dillon  *
14e25c779eSMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15e25c779eSMatthew Dillon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16e25c779eSMatthew Dillon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17e25c779eSMatthew Dillon  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18e25c779eSMatthew Dillon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19e25c779eSMatthew Dillon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20e25c779eSMatthew Dillon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21e25c779eSMatthew Dillon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22e25c779eSMatthew Dillon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23e25c779eSMatthew Dillon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24e25c779eSMatthew Dillon  * SUCH DAMAGE.
25e25c779eSMatthew Dillon  *
26e25c779eSMatthew Dillon  */
27e25c779eSMatthew Dillon 
28e25c779eSMatthew Dillon /*
29e25c779eSMatthew Dillon  | $Id: fsm.c,v 2.8 2007/05/19 16:34:21 danny Exp danny $
30e25c779eSMatthew Dillon  */
31e25c779eSMatthew Dillon 
32e25c779eSMatthew Dillon #include <sys/param.h>
33e25c779eSMatthew Dillon #include <sys/types.h>
34e25c779eSMatthew Dillon #include <sys/socket.h>
35e25c779eSMatthew Dillon #include <sys/sysctl.h>
36e25c779eSMatthew Dillon 
37e25c779eSMatthew Dillon #include <netinet/in.h>
38e25c779eSMatthew Dillon #include <netinet/tcp.h>
39e25c779eSMatthew Dillon #include <arpa/inet.h>
40e25c779eSMatthew Dillon #include <sys/ioctl.h>
41e25c779eSMatthew Dillon #include <netdb.h>
42e25c779eSMatthew Dillon #include <stdlib.h>
43e25c779eSMatthew Dillon #include <unistd.h>
44e25c779eSMatthew Dillon #include <stdio.h>
45e25c779eSMatthew Dillon #include <string.h>
46e25c779eSMatthew Dillon #include <errno.h>
47e25c779eSMatthew Dillon #include <fcntl.h>
48e25c779eSMatthew Dillon #include <time.h>
49e25c779eSMatthew Dillon #include <syslog.h>
50e25c779eSMatthew Dillon #include <stdarg.h>
51e25c779eSMatthew Dillon #include <camlib.h>
52e25c779eSMatthew Dillon 
53e25c779eSMatthew Dillon #include "iscsi.h"
54e25c779eSMatthew Dillon #include "iscontrol.h"
55e25c779eSMatthew Dillon 
56e25c779eSMatthew Dillon typedef enum {
57e25c779eSMatthew Dillon      T1 = 1,
58e25c779eSMatthew Dillon      T2, /*T3,*/ T4, T5, /*T6,*/ T7, T8, T9,
59e25c779eSMatthew Dillon      T10, T11, T12, T13, T14, T15, T16, T18
60e25c779eSMatthew Dillon } trans_t;
61e25c779eSMatthew Dillon 
62e25c779eSMatthew Dillon /*
63e25c779eSMatthew Dillon  | now supports IPV6
64e25c779eSMatthew Dillon  | thanks to:
65e25c779eSMatthew Dillon  |	Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan
66e25c779eSMatthew Dillon  |	ume@mahoroba.org  ume@{,jp.}FreeBSD.org
67e25c779eSMatthew Dillon  |	http://www.imasy.org/~ume/
68e25c779eSMatthew Dillon  */
69e25c779eSMatthew Dillon static trans_t
tcpConnect(isess_t * sess)70e25c779eSMatthew Dillon tcpConnect(isess_t *sess)
71e25c779eSMatthew Dillon {
72e25c779eSMatthew Dillon      isc_opt_t *op = sess->op;
73e25c779eSMatthew Dillon      int	val, sv_errno, soc;
74e25c779eSMatthew Dillon      struct     addrinfo *res, *res0, hints;
75e25c779eSMatthew Dillon      char	pbuf[10];
76e25c779eSMatthew Dillon 
77e25c779eSMatthew Dillon      debug_called(3);
78e25c779eSMatthew Dillon      if(sess->flags & (SESS_RECONNECT|SESS_REDIRECT)) {
79e25c779eSMatthew Dillon 	  syslog(LOG_INFO, "%s", (sess->flags & SESS_RECONNECT)
80e25c779eSMatthew Dillon 		 ? "Reconnect": "Redirected");
81e25c779eSMatthew Dillon 
82e25c779eSMatthew Dillon 	  debug(1, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected");
83e25c779eSMatthew Dillon 	  shutdown(sess->soc, SHUT_RDWR);
84e25c779eSMatthew Dillon 	  //close(sess->soc);
85e25c779eSMatthew Dillon 	  sess->soc = -1;
86e25c779eSMatthew Dillon 
87e25c779eSMatthew Dillon 	  sess->flags &= ~SESS_CONNECTED;
88e25c779eSMatthew Dillon 	  if(sess->flags & SESS_REDIRECT) {
89e25c779eSMatthew Dillon 	       sess->redirect_cnt++;
90e25c779eSMatthew Dillon 	       sess->flags |= SESS_RECONNECT;
91e25c779eSMatthew Dillon 	  } else
92e25c779eSMatthew Dillon 	       sleep(2); // XXX: actually should be ?
93e25c779eSMatthew Dillon #ifdef notyet
94e25c779eSMatthew Dillon 	  {
95e25c779eSMatthew Dillon 	       time_t	sec;
96e25c779eSMatthew Dillon 	  // make sure we are not in a loop
97e25c779eSMatthew Dillon 	  // XXX: this code has to be tested
98e25c779eSMatthew Dillon 	  sec = time(0) - sess->reconnect_time;
99e25c779eSMatthew Dillon 	  if(sec > (5*60)) {
100e25c779eSMatthew Dillon 	       // if we've been connected for more that 5 minutes
101e25c779eSMatthew Dillon 	       // then just reconnect
102e25c779eSMatthew Dillon 	       sess->reconnect_time = sec;
103e25c779eSMatthew Dillon 	       sess->reconnect_cnt1 = 0;
104e25c779eSMatthew Dillon 	  }
105e25c779eSMatthew Dillon 	  else {
106e25c779eSMatthew Dillon 	       //
107e25c779eSMatthew Dillon 	       sess->reconnect_cnt1++;
108e25c779eSMatthew Dillon 	       if((sec / sess->reconnect_cnt1) < 2) {
109e25c779eSMatthew Dillon 		    // if less that 2 seconds from the last reconnect
110e25c779eSMatthew Dillon 		    // we are most probably looping
111e25c779eSMatthew Dillon 		    syslog(LOG_CRIT, "too many reconnects %d", sess->reconnect_cnt1);
112e25c779eSMatthew Dillon 		    return 0;
113e25c779eSMatthew Dillon 	       }
114e25c779eSMatthew Dillon 	  }
115e25c779eSMatthew Dillon      }
116e25c779eSMatthew Dillon #endif
117e25c779eSMatthew Dillon 	  sess->reconnect_cnt++;
118e25c779eSMatthew Dillon      }
119e25c779eSMatthew Dillon 
120e25c779eSMatthew Dillon      snprintf(pbuf, sizeof(pbuf), "%d", op->port);
121e25c779eSMatthew Dillon      memset(&hints, 0, sizeof(hints));
122e25c779eSMatthew Dillon      hints.ai_family	= PF_UNSPEC;
123e25c779eSMatthew Dillon      hints.ai_socktype	= SOCK_STREAM;
124e25c779eSMatthew Dillon      debug(1, "targetAddress=%s port=%d", op->targetAddress, op->port);
125e25c779eSMatthew Dillon      if((val = getaddrinfo(op->targetAddress, pbuf, &hints, &res0)) != 0) {
126e25c779eSMatthew Dillon           fprintf(stderr, "getaddrinfo(%s): %s\n", op->targetAddress, gai_strerror(val));
127e25c779eSMatthew Dillon           return 0;
128e25c779eSMatthew Dillon      }
129e25c779eSMatthew Dillon      sess->flags &= ~SESS_CONNECTED;
130e25c779eSMatthew Dillon      sv_errno = 0;
131e25c779eSMatthew Dillon      soc = -1;
132e25c779eSMatthew Dillon      for(res = res0; res; res = res->ai_next) {
133e25c779eSMatthew Dillon 	  soc = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
134e25c779eSMatthew Dillon 	  if (soc == -1)
135e25c779eSMatthew Dillon 	       continue;
136e25c779eSMatthew Dillon 
137e25c779eSMatthew Dillon      // from Patrick.Guelat@imp.ch:
138e25c779eSMatthew Dillon      // iscontrol can be called without waiting for the socket entry to time out
139e25c779eSMatthew Dillon 	  val = 1;
140e25c779eSMatthew Dillon 	  if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) {
141e25c779eSMatthew Dillon 		  fprintf(stderr, "Cannot set socket SO_REUSEADDR %d: %s\n\n",
142e25c779eSMatthew Dillon 				  errno, strerror(errno));
143e25c779eSMatthew Dillon 	  }
144e25c779eSMatthew Dillon 	  if(connect(soc, res->ai_addr, res->ai_addrlen) == 0)
145e25c779eSMatthew Dillon 	     break;
146e25c779eSMatthew Dillon 
147e25c779eSMatthew Dillon 	  sv_errno = errno;
148e25c779eSMatthew Dillon 	  close(soc);
149e25c779eSMatthew Dillon 	  soc = -1;
150e25c779eSMatthew Dillon      }
151e25c779eSMatthew Dillon      freeaddrinfo(res0);
152e25c779eSMatthew Dillon 
153e25c779eSMatthew Dillon      if(soc != -1) {
154e25c779eSMatthew Dillon 	  sess->soc = soc;
155e25c779eSMatthew Dillon 
156e25c779eSMatthew Dillon 	  /* Default to TCP_NODELAY to improve transfers */
157e25c779eSMatthew Dillon 	  if(setsockopt(sess->soc, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0)
158e25c779eSMatthew Dillon 		  fprintf(stderr, "Cannot set socket NO delay option err=%d %s\n",
159e25c779eSMatthew Dillon 				  errno, strerror(errno));
160e25c779eSMatthew Dillon 
161e25c779eSMatthew Dillon #if 0
162e25c779eSMatthew Dillon 	  struct	timeval timeout;
163e25c779eSMatthew Dillon 
164e25c779eSMatthew Dillon 	  val = 1;
165e25c779eSMatthew Dillon 	  if(setsockopt(sess->soc, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0)
166e25c779eSMatthew Dillon 	       fprintf(stderr, "Cannot set socket KEEPALIVE option err=%d %s\n",
167e25c779eSMatthew Dillon 		       errno, strerror(errno));
168e25c779eSMatthew Dillon 
169e25c779eSMatthew Dillon 	  if(setsockopt(sess->soc, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) < 0)
170e25c779eSMatthew Dillon 	       fprintf(stderr, "Cannot set socket NO delay option err=%d %s\n",
171e25c779eSMatthew Dillon 		       errno, strerror(errno));
172e25c779eSMatthew Dillon 
173e25c779eSMatthew Dillon 	  timeout.tv_sec = 10;
174e25c779eSMatthew Dillon 	  timeout.tv_usec = 0;
175e25c779eSMatthew Dillon 	  if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0)
176e25c779eSMatthew Dillon 	     || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)) {
177e25c779eSMatthew Dillon 	       fprintf(stderr, "Cannot set socket timeout to %ld err=%d %s\n",
178e25c779eSMatthew Dillon 		       timeout.tv_sec, errno, strerror(errno));
179e25c779eSMatthew Dillon 	  }
180e25c779eSMatthew Dillon #endif
181e25c779eSMatthew Dillon #ifdef CURIOUS
182e25c779eSMatthew Dillon 	  {
183e25c779eSMatthew Dillon 	       int len = sizeof(val);
184e25c779eSMatthew Dillon 	       if(getsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, &len) == 0)
185e25c779eSMatthew Dillon 		    fprintf(stderr, "was: SO_SNDBUF=%dK\n", val/1024);
186e25c779eSMatthew Dillon 	  }
187e25c779eSMatthew Dillon #endif
188e25c779eSMatthew Dillon 	  if(sess->op->sockbufsize) {
189e25c779eSMatthew Dillon 	       val = sess->op->sockbufsize * 1024;
190e25c779eSMatthew Dillon 	       if((setsockopt(sess->soc, SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)) < 0)
191e25c779eSMatthew Dillon 		  || (setsockopt(sess->soc, SOL_SOCKET, SO_RCVBUF, &val, sizeof(val)) < 0)) {
192e25c779eSMatthew Dillon 		    fprintf(stderr, "Cannot set socket sndbuf & rcvbuf to %d err=%d %s\n",
193e25c779eSMatthew Dillon 			    val, errno, strerror(errno));
194e25c779eSMatthew Dillon 		    return 0;
195e25c779eSMatthew Dillon 	       }
196e25c779eSMatthew Dillon 	  }
197e25c779eSMatthew Dillon 	  sess->flags |= SESS_CONNECTED;
198e25c779eSMatthew Dillon 	  return T1;
199e25c779eSMatthew Dillon      }
200e25c779eSMatthew Dillon 
201e25c779eSMatthew Dillon      fprintf(stderr, "errno=%d\n", sv_errno);
202e25c779eSMatthew Dillon      perror("connect");
203e25c779eSMatthew Dillon      switch(sv_errno) {
204e25c779eSMatthew Dillon      case ECONNREFUSED:
205e25c779eSMatthew Dillon      case ENETUNREACH:
206e25c779eSMatthew Dillon      case ETIMEDOUT:
207e25c779eSMatthew Dillon 	  if((sess->flags & SESS_REDIRECT) == 0) {
208e25c779eSMatthew Dillon 	       if(strcmp(op->targetAddress, sess->target.address) != 0) {
209e25c779eSMatthew Dillon 		    syslog(LOG_INFO, "reconnecting to original target address");
210e25c779eSMatthew Dillon 		    free(op->targetAddress);
211e25c779eSMatthew Dillon 		    op->targetAddress           = sess->target.address;
212e25c779eSMatthew Dillon 		    op->port                    = sess->target.port;
213e25c779eSMatthew Dillon 		    op->targetPortalGroupTag    = sess->target.pgt;
214e25c779eSMatthew Dillon 		    return T1;
215e25c779eSMatthew Dillon 	       }
216e25c779eSMatthew Dillon 	  }
217e25c779eSMatthew Dillon 	  sleep(5); // for now ...
218e25c779eSMatthew Dillon 	  return T1;
219e25c779eSMatthew Dillon      default:
220e25c779eSMatthew Dillon 	  return 0; // terminal error
221e25c779eSMatthew Dillon      }
222e25c779eSMatthew Dillon }
223e25c779eSMatthew Dillon 
224e25c779eSMatthew Dillon int
setOptions(isess_t * sess,int flag)225e25c779eSMatthew Dillon setOptions(isess_t *sess, int flag)
226e25c779eSMatthew Dillon {
227e25c779eSMatthew Dillon      isc_opt_t	oop;
228e25c779eSMatthew Dillon      char	*sep;
229e25c779eSMatthew Dillon 
230e25c779eSMatthew Dillon      debug_called(3);
231e25c779eSMatthew Dillon 
232e25c779eSMatthew Dillon      bzero(&oop, sizeof(isc_opt_t));
233e25c779eSMatthew Dillon 
234e25c779eSMatthew Dillon      if((flag & SESS_FULLFEATURE) == 0) {
235e25c779eSMatthew Dillon 	  oop.initiatorName	= sess->op->initiatorName;
236e25c779eSMatthew Dillon 	  oop.targetAddress	= sess->op->targetAddress;
237e25c779eSMatthew Dillon 	  if(sess->op->targetName != 0)
238e25c779eSMatthew Dillon 	       oop.targetName = sess->op->targetName;
239e25c779eSMatthew Dillon 
240e25c779eSMatthew Dillon 	  oop.maxRecvDataSegmentLength = sess->op->maxRecvDataSegmentLength;
241e25c779eSMatthew Dillon 	  oop.maxXmitDataSegmentLength = sess->op->maxXmitDataSegmentLength; // XXX:
242e25c779eSMatthew Dillon 	  oop.maxBurstLength = sess->op->maxBurstLength;
243e25c779eSMatthew Dillon 	  oop.maxluns = sess->op->maxluns;
244e25c779eSMatthew Dillon      }
245e25c779eSMatthew Dillon      else {
246e25c779eSMatthew Dillon 	  /*
247e25c779eSMatthew Dillon 	   | turn on digestion only after login
248e25c779eSMatthew Dillon 	   */
249e25c779eSMatthew Dillon 	  if(sess->op->headerDigest != NULL) {
250e25c779eSMatthew Dillon 	       sep = strchr(sess->op->headerDigest, ',');
251e25c779eSMatthew Dillon 	       if(sep == NULL)
252e25c779eSMatthew Dillon 		    oop.headerDigest = sess->op->headerDigest;
253e25c779eSMatthew Dillon 	       debug(1, "oop.headerDigest=%s", oop.headerDigest);
254e25c779eSMatthew Dillon 	  }
255e25c779eSMatthew Dillon 	  if(sess->op->dataDigest != NULL) {
256e25c779eSMatthew Dillon 	       sep = strchr(sess->op->dataDigest, ',');
257e25c779eSMatthew Dillon 	       if(sep == NULL)
258e25c779eSMatthew Dillon 		    oop.dataDigest = sess->op->dataDigest;
259e25c779eSMatthew Dillon 	       debug(1, "oop.dataDigest=%s", oop.dataDigest);
260e25c779eSMatthew Dillon 	  }
261e25c779eSMatthew Dillon      }
262e25c779eSMatthew Dillon 
263e25c779eSMatthew Dillon      if(ioctl(sess->fd, ISCSISETOPT, &oop)) {
264e25c779eSMatthew Dillon 	  perror("ISCSISETOPT");
265e25c779eSMatthew Dillon 	  return -1;
266e25c779eSMatthew Dillon      }
267e25c779eSMatthew Dillon      return 0;
268e25c779eSMatthew Dillon }
269e25c779eSMatthew Dillon 
270e25c779eSMatthew Dillon static trans_t
startSession(isess_t * sess)271e25c779eSMatthew Dillon startSession(isess_t *sess)
272e25c779eSMatthew Dillon {
273e25c779eSMatthew Dillon 
274e25c779eSMatthew Dillon      int	n, fd, nfd;
275e25c779eSMatthew Dillon      char	*dev;
276e25c779eSMatthew Dillon 
277e25c779eSMatthew Dillon      debug_called(3);
278e25c779eSMatthew Dillon 
279e25c779eSMatthew Dillon      if((sess->flags & SESS_CONNECTED) == 0) {
280e25c779eSMatthew Dillon 	  return T2;
281e25c779eSMatthew Dillon      }
282e25c779eSMatthew Dillon      if(sess->fd == -1) {
283e25c779eSMatthew Dillon 	  fd = open(iscsidev, O_RDWR);
284e25c779eSMatthew Dillon 	  if(fd < 0) {
285e25c779eSMatthew Dillon 	       perror(iscsidev);
286e25c779eSMatthew Dillon 	       return 0;
287e25c779eSMatthew Dillon 	  }
288e25c779eSMatthew Dillon 	  {
289e25c779eSMatthew Dillon 	       // XXX: this has to go
290e25c779eSMatthew Dillon 	       size_t	n;
291e25c779eSMatthew Dillon 	       n = sizeof(sess->isid);
292e25c779eSMatthew Dillon 	       if(sysctlbyname("net.iscsi.isid", (void *)sess->isid, (size_t *)&n, 0, 0) != 0)
293e25c779eSMatthew Dillon 		    perror("sysctlbyname");
294e25c779eSMatthew Dillon 	  }
295e25c779eSMatthew Dillon 	  if(ioctl(fd, ISCSISETSES, &n)) {
296e25c779eSMatthew Dillon 	       perror("ISCSISETSES");
297e25c779eSMatthew Dillon 	       return 0;
298e25c779eSMatthew Dillon 	  }
299e25c779eSMatthew Dillon 	  sleep(1);	/* XXX temporary */
300e25c779eSMatthew Dillon 	  asprintf(&dev, "%s%d", iscsidev, n);
301e25c779eSMatthew Dillon 	  nfd = open(dev, O_RDWR);
302e25c779eSMatthew Dillon 	  if(nfd < 0) {
303e25c779eSMatthew Dillon 	       perror(dev);
304e25c779eSMatthew Dillon 	       free(dev);
305e25c779eSMatthew Dillon 	       return 0;
306e25c779eSMatthew Dillon 	  }
307e25c779eSMatthew Dillon 	  free(dev);
308e25c779eSMatthew Dillon 	  close(fd);
309e25c779eSMatthew Dillon 	  sess->fd = nfd;
310e25c779eSMatthew Dillon 
311e25c779eSMatthew Dillon 	  if(setOptions(sess, 0) != 0)
312e25c779eSMatthew Dillon 	       return -1;
313e25c779eSMatthew Dillon      }
314e25c779eSMatthew Dillon 
315e25c779eSMatthew Dillon      if(ioctl(sess->fd, ISCSISETSOC, &sess->soc)) {
316e25c779eSMatthew Dillon 	  perror("ISCSISETSOC");
317e25c779eSMatthew Dillon 	  return 0;
318e25c779eSMatthew Dillon      }
319e25c779eSMatthew Dillon 
320e25c779eSMatthew Dillon      return T4;
321e25c779eSMatthew Dillon }
322e25c779eSMatthew Dillon 
323*d50f9ae3SSascha Wildner static isess_t *currsess;
324e25c779eSMatthew Dillon 
325e25c779eSMatthew Dillon static void
trap(int sig)326e25c779eSMatthew Dillon trap(int sig)
327e25c779eSMatthew Dillon {
328e25c779eSMatthew Dillon      syslog(LOG_NOTICE, "trapped signal %d", sig);
329e25c779eSMatthew Dillon      fprintf(stderr, "trapped signal %d\n", sig);
330e25c779eSMatthew Dillon 
331e25c779eSMatthew Dillon      switch(sig) {
332e25c779eSMatthew Dillon      case SIGHUP:
333e25c779eSMatthew Dillon 	  currsess->flags |= SESS_DISCONNECT;
334e25c779eSMatthew Dillon 	  break;
335e25c779eSMatthew Dillon 
336e25c779eSMatthew Dillon      case SIGUSR1:
337e25c779eSMatthew Dillon 	  currsess->flags |= SESS_RECONNECT;
338e25c779eSMatthew Dillon 	  break;
339e25c779eSMatthew Dillon 
340e25c779eSMatthew Dillon      case SIGINT:
341e25c779eSMatthew Dillon      case SIGTERM:
342e25c779eSMatthew Dillon      default:
343e25c779eSMatthew Dillon 	  return; // ignore
344e25c779eSMatthew Dillon      }
345e25c779eSMatthew Dillon }
346e25c779eSMatthew Dillon 
347e25c779eSMatthew Dillon static void
doCAM(isess_t * sess)348e25c779eSMatthew Dillon doCAM(isess_t *sess)
349e25c779eSMatthew Dillon {
350e25c779eSMatthew Dillon      char	pathstr[1024];
351e25c779eSMatthew Dillon      union ccb	*ccb;
352e25c779eSMatthew Dillon      int	i;
353e25c779eSMatthew Dillon 
354e25c779eSMatthew Dillon      if(ioctl(sess->fd, ISCSIGETCAM, &sess->cam) != 0) {
355e25c779eSMatthew Dillon 	  syslog(LOG_WARNING, "ISCSIGETCAM failed: %d", errno);
356e25c779eSMatthew Dillon 	  return;
357e25c779eSMatthew Dillon      }
358e25c779eSMatthew Dillon      debug(2, "nluns=%d", sess->cam.target_nluns);
359e25c779eSMatthew Dillon      /*
360e25c779eSMatthew Dillon       | for now will do this for each lun ...
361e25c779eSMatthew Dillon       */
362e25c779eSMatthew Dillon      for(i = 0; i < sess->cam.target_nluns; i++) {
363e25c779eSMatthew Dillon 	  debug(2, "CAM path_id=%d target_id=%d target_lun=%d",
364e25c779eSMatthew Dillon 		sess->cam.path_id, sess->cam.target_id, sess->cam.target_lun[i]);
365e25c779eSMatthew Dillon 
366e25c779eSMatthew Dillon 	  sess->camdev = cam_open_btl(sess->cam.path_id, sess->cam.target_id,
367e25c779eSMatthew Dillon 				      sess->cam.target_lun[i], O_RDWR, NULL);
368e25c779eSMatthew Dillon 	  if(sess->camdev == NULL) {
369e25c779eSMatthew Dillon 	       syslog(LOG_WARNING, "%s", cam_errbuf);
370e25c779eSMatthew Dillon 	       debug(3, "%s", cam_errbuf);
371e25c779eSMatthew Dillon 	       continue;
372e25c779eSMatthew Dillon 	  }
373e25c779eSMatthew Dillon 
374e25c779eSMatthew Dillon 	  cam_path_string(sess->camdev, pathstr, sizeof(pathstr));
375e25c779eSMatthew Dillon 	  debug(2, "pathstr=%s", pathstr);
376e25c779eSMatthew Dillon 
377e25c779eSMatthew Dillon 	  ccb = cam_getccb(sess->camdev);
378e25c779eSMatthew Dillon 	  bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_relsim) - sizeof(struct ccb_hdr));
379e25c779eSMatthew Dillon 	  ccb->ccb_h.func_code = XPT_REL_SIMQ;
380e25c779eSMatthew Dillon 	  ccb->crs.release_flags = RELSIM_ADJUST_OPENINGS;
381e25c779eSMatthew Dillon 	  ccb->crs.openings = sess->op->tags;
382e25c779eSMatthew Dillon 
383e25c779eSMatthew Dillon 	  if(cam_send_ccb(sess->camdev, ccb) < 0)
384e25c779eSMatthew Dillon 	       syslog(LOG_WARNING, "%s", cam_errbuf);
385e25c779eSMatthew Dillon 	  else
386e25c779eSMatthew Dillon 	  if((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
387e25c779eSMatthew Dillon 	       syslog(LOG_WARNING, "XPT_REL_SIMQ CCB failed");
388e25c779eSMatthew Dillon 	       // cam_error_print(sess->camdev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
389e25c779eSMatthew Dillon 	  }
390e25c779eSMatthew Dillon 	  else
391e25c779eSMatthew Dillon 	       syslog(LOG_INFO, "%s tagged openings now %d\n", pathstr, ccb->crs.openings);
392e25c779eSMatthew Dillon 
393e25c779eSMatthew Dillon 	  cam_freeccb(ccb);
394e25c779eSMatthew Dillon 	  cam_close_device(sess->camdev);
395e25c779eSMatthew Dillon      }
396e25c779eSMatthew Dillon }
397e25c779eSMatthew Dillon 
398e25c779eSMatthew Dillon static trans_t
supervise(isess_t * sess)399e25c779eSMatthew Dillon supervise(isess_t *sess)
400e25c779eSMatthew Dillon {
401e25c779eSMatthew Dillon      int	sig, val;
402e25c779eSMatthew Dillon 
403e25c779eSMatthew Dillon      debug_called(3);
404e25c779eSMatthew Dillon 
405e25c779eSMatthew Dillon      if(strcmp(sess->op->sessionType, "Discovery") == 0) {
406e25c779eSMatthew Dillon 	  sess->flags |= SESS_DISCONNECT;
407e25c779eSMatthew Dillon 	  return T9;
408e25c779eSMatthew Dillon      }
409e25c779eSMatthew Dillon 
410e25c779eSMatthew Dillon      if(vflag)
411e25c779eSMatthew Dillon 	  printf("ready to go scsi\n");
412e25c779eSMatthew Dillon 
413e25c779eSMatthew Dillon      if(setOptions(sess, SESS_FULLFEATURE) != 0)
414e25c779eSMatthew Dillon 	  return 0; // failure
415e25c779eSMatthew Dillon 
416e25c779eSMatthew Dillon      if((sess->flags & SESS_FULLFEATURE) == 0) {
417e25c779eSMatthew Dillon 	  if(daemon(0, 1) != 0) {
418e25c779eSMatthew Dillon 	       perror("daemon");
419e25c779eSMatthew Dillon 	       exit(1);
420e25c779eSMatthew Dillon 	  }
421e25c779eSMatthew Dillon 
422e25c779eSMatthew Dillon 	  openlog("iscontrol", LOG_CONS|LOG_PERROR|LOG_PID|LOG_NDELAY, LOG_KERN);
423e25c779eSMatthew Dillon 	  syslog(LOG_INFO, "running");
424e25c779eSMatthew Dillon 
425e25c779eSMatthew Dillon 	  currsess = sess;
426e25c779eSMatthew Dillon 	  if(ioctl(sess->fd, ISCSISTART)) {
427e25c779eSMatthew Dillon 	       perror("ISCSISTART");
428e25c779eSMatthew Dillon 	       return -1;
429e25c779eSMatthew Dillon 	  }
430e25c779eSMatthew Dillon 	  doCAM(sess);
431e25c779eSMatthew Dillon 
432e25c779eSMatthew Dillon      }
433e25c779eSMatthew Dillon      else {
434e25c779eSMatthew Dillon 	  if(ioctl(sess->fd, ISCSIRESTART)) {
435e25c779eSMatthew Dillon 	       perror("ISCSIRESTART");
436e25c779eSMatthew Dillon 	       return -1;
437e25c779eSMatthew Dillon 	  }
438e25c779eSMatthew Dillon      }
439e25c779eSMatthew Dillon 
440e25c779eSMatthew Dillon      signal(SIGINT, trap);
441e25c779eSMatthew Dillon      signal(SIGHUP, trap);
442e25c779eSMatthew Dillon      signal(SIGTERM, trap);
443e25c779eSMatthew Dillon 
444e25c779eSMatthew Dillon      sig = SIGUSR1;
445e25c779eSMatthew Dillon      signal(sig, trap);
446e25c779eSMatthew Dillon      if(ioctl(sess->fd, ISCSISIGNAL, &sig)) {
447e25c779eSMatthew Dillon 	  perror("ISCSISIGNAL");
448e25c779eSMatthew Dillon 	  return -1;
449e25c779eSMatthew Dillon      }
450e25c779eSMatthew Dillon      sess->flags |= SESS_FULLFEATURE;
451e25c779eSMatthew Dillon 
452e25c779eSMatthew Dillon      sess->flags &= ~(SESS_REDIRECT | SESS_RECONNECT);
453e25c779eSMatthew Dillon      printf("iscontrol: supervise starting main loop\n");
454e25c779eSMatthew Dillon      /*
455e25c779eSMatthew Dillon       | the main loop - actually do nothing
456e25c779eSMatthew Dillon       | all the work is done inside the kernel
457e25c779eSMatthew Dillon       */
458e25c779eSMatthew Dillon      while((sess->flags & (SESS_REDIRECT|SESS_RECONNECT|SESS_DISCONNECT)) == 0) {
459e25c779eSMatthew Dillon 	  // do something?
460e25c779eSMatthew Dillon 	  // like sending a nop_out?
461e25c779eSMatthew Dillon 	  sleep(60);
462e25c779eSMatthew Dillon      }
463e25c779eSMatthew Dillon      printf("iscontrol: supervise going down\n");
464e25c779eSMatthew Dillon      syslog(LOG_INFO, "sess flags=%x", sess->flags);
465e25c779eSMatthew Dillon 
466e25c779eSMatthew Dillon      sig = 0;
467e25c779eSMatthew Dillon      if(ioctl(sess->fd, ISCSISIGNAL, &sig)) {
468e25c779eSMatthew Dillon 	  perror("ISCSISIGNAL");
469e25c779eSMatthew Dillon      }
470e25c779eSMatthew Dillon 
471e25c779eSMatthew Dillon      if(sess->flags & SESS_DISCONNECT) {
472e25c779eSMatthew Dillon 	  val = 0;
473e25c779eSMatthew Dillon 	  if(ioctl(sess->fd, ISCSISTOP, &val)) {
474e25c779eSMatthew Dillon 	       perror("ISCSISTOP");
475e25c779eSMatthew Dillon 	  }
476e25c779eSMatthew Dillon 	  sess->flags &= ~SESS_FULLFEATURE;
477e25c779eSMatthew Dillon 	  return T9;
478e25c779eSMatthew Dillon      }
479e25c779eSMatthew Dillon      else {
480e25c779eSMatthew Dillon 	  sess->flags |= SESS_INITIALLOGIN1;
481e25c779eSMatthew Dillon      }
482e25c779eSMatthew Dillon      return T8;
483e25c779eSMatthew Dillon }
484e25c779eSMatthew Dillon 
485e25c779eSMatthew Dillon static int
handledDiscoveryResp(isess_t * sess,pdu_t * pp)486e25c779eSMatthew Dillon handledDiscoveryResp(isess_t *sess, pdu_t *pp)
487e25c779eSMatthew Dillon {
488e25c779eSMatthew Dillon      u_char	*ptr;
489e25c779eSMatthew Dillon      int	len, n;
490e25c779eSMatthew Dillon 
491e25c779eSMatthew Dillon      debug_called(3);
492e25c779eSMatthew Dillon 
493e25c779eSMatthew Dillon      len = pp->ds_len;
494e25c779eSMatthew Dillon      ptr = pp->ds;
495e25c779eSMatthew Dillon      while(len > 0) {
496e25c779eSMatthew Dillon 	  if(*ptr != 0)
497e25c779eSMatthew Dillon 	       printf("%s\n", ptr);
498e25c779eSMatthew Dillon 	  n = strlen((char *)ptr) + 1;
499e25c779eSMatthew Dillon 	  len -= n;
500e25c779eSMatthew Dillon 	  ptr += n;
501e25c779eSMatthew Dillon      }
502e25c779eSMatthew Dillon      return 0;
503e25c779eSMatthew Dillon }
504e25c779eSMatthew Dillon 
505e25c779eSMatthew Dillon static int
doDiscovery(isess_t * sess)506e25c779eSMatthew Dillon doDiscovery(isess_t *sess)
507e25c779eSMatthew Dillon {
508e25c779eSMatthew Dillon      pdu_t	spp;
509e25c779eSMatthew Dillon      text_req_t	*tp = (text_req_t *)&spp.ipdu.bhs;
510e25c779eSMatthew Dillon 
511e25c779eSMatthew Dillon      debug_called(3);
512e25c779eSMatthew Dillon 
513e25c779eSMatthew Dillon      bzero(&spp, sizeof(pdu_t));
514e25c779eSMatthew Dillon      tp->cmd = ISCSI_TEXT_CMD /*| 0x40 */; // because of a bug in openiscsi-target
515e25c779eSMatthew Dillon      tp->F = 1;
516e25c779eSMatthew Dillon      tp->ttt = 0xffffffff;
517e25c779eSMatthew Dillon      addText(&spp, "SendTargets=All");
518e25c779eSMatthew Dillon      return sendPDU(sess, &spp, handledDiscoveryResp);
519e25c779eSMatthew Dillon }
520e25c779eSMatthew Dillon 
521e25c779eSMatthew Dillon static trans_t
doLogin(isess_t * sess)522e25c779eSMatthew Dillon doLogin(isess_t *sess)
523e25c779eSMatthew Dillon {
524e25c779eSMatthew Dillon      isc_opt_t	*op = sess->op;
525e25c779eSMatthew Dillon      int	status, count;
526e25c779eSMatthew Dillon 
527e25c779eSMatthew Dillon      debug_called(3);
528e25c779eSMatthew Dillon 
529e25c779eSMatthew Dillon      if(op->chapSecret == NULL && op->tgtChapSecret == NULL)
530e25c779eSMatthew Dillon 	  /*
531e25c779eSMatthew Dillon 	   | don't need any security negotiation
532e25c779eSMatthew Dillon 	   | or in other words: we don't have any secrets to exchange
533e25c779eSMatthew Dillon 	   */
534e25c779eSMatthew Dillon 	  sess->csg = LON_PHASE;
535e25c779eSMatthew Dillon      else
536e25c779eSMatthew Dillon 	  sess->csg = SN_PHASE;
537e25c779eSMatthew Dillon 
538e25c779eSMatthew Dillon      if(sess->tsih) {
539e25c779eSMatthew Dillon 	  sess->tsih = 0;	// XXX: no 'reconnect' yet
540e25c779eSMatthew Dillon 	  sess->flags &= ~SESS_NEGODONE; // XXX: KLUDGE
541e25c779eSMatthew Dillon      }
542e25c779eSMatthew Dillon      count = 10; // should be more than enough
543e25c779eSMatthew Dillon      do {
544e25c779eSMatthew Dillon 	  debug(3, "count=%d csg=%d", count, sess->csg);
545e25c779eSMatthew Dillon 	  status = loginPhase(sess);
546e25c779eSMatthew Dillon 	  if(count-- == 0)
547e25c779eSMatthew Dillon 	       // just in case we get into a loop
548e25c779eSMatthew Dillon 	       status = -1;
549e25c779eSMatthew Dillon      } while(status == 0 && (sess->csg != FF_PHASE));
550e25c779eSMatthew Dillon 
551e25c779eSMatthew Dillon      sess->flags &= ~SESS_INITIALLOGIN;
552e25c779eSMatthew Dillon      debug(3, "status=%d", status);
553e25c779eSMatthew Dillon 
554e25c779eSMatthew Dillon      switch(status) {
555e25c779eSMatthew Dillon      case 0: // all is ok ...
556e25c779eSMatthew Dillon 	  sess->flags |= SESS_LOGGEDIN;
557e25c779eSMatthew Dillon 	  if(strcmp(sess->op->sessionType, "Discovery") == 0)
558e25c779eSMatthew Dillon 	       doDiscovery(sess);
559e25c779eSMatthew Dillon 	  return T5;
560e25c779eSMatthew Dillon 
561e25c779eSMatthew Dillon      case 1:	// redirect - temporary/permanent
562e25c779eSMatthew Dillon 	  /*
563e25c779eSMatthew Dillon 	   | start from scratch?
564e25c779eSMatthew Dillon 	   */
565e25c779eSMatthew Dillon 	  sess->flags &= ~SESS_NEGODONE;
566e25c779eSMatthew Dillon 	  sess->flags |= (SESS_REDIRECT | SESS_INITIALLOGIN1);
567e25c779eSMatthew Dillon 	  syslog(LOG_DEBUG, "target sent REDIRECT");
568e25c779eSMatthew Dillon 	  return T7;
569e25c779eSMatthew Dillon 
570e25c779eSMatthew Dillon      case 2: // initiator terminal error
571e25c779eSMatthew Dillon 	  return 0;
572e25c779eSMatthew Dillon      case 3: // target terminal error -- could retry ...
573e25c779eSMatthew Dillon 	  sleep(5);
574e25c779eSMatthew Dillon 	  return T7; // lets try
575e25c779eSMatthew Dillon      default:
576e25c779eSMatthew Dillon 	  return 0;
577e25c779eSMatthew Dillon      }
578e25c779eSMatthew Dillon }
579e25c779eSMatthew Dillon 
580e25c779eSMatthew Dillon static int
handleLogoutResp(isess_t * sess,pdu_t * pp)581e25c779eSMatthew Dillon handleLogoutResp(isess_t *sess, pdu_t *pp)
582e25c779eSMatthew Dillon {
583e25c779eSMatthew Dillon      if(sess->flags & SESS_DISCONNECT)
584e25c779eSMatthew Dillon 	  return 0;
585e25c779eSMatthew Dillon      return T13;
586e25c779eSMatthew Dillon }
587e25c779eSMatthew Dillon 
588e25c779eSMatthew Dillon static trans_t
startLogout(isess_t * sess)589e25c779eSMatthew Dillon startLogout(isess_t *sess)
590e25c779eSMatthew Dillon {
591e25c779eSMatthew Dillon      pdu_t	spp;
592e25c779eSMatthew Dillon      logout_req_t *p = (logout_req_t *)&spp.ipdu.bhs;
593e25c779eSMatthew Dillon 
594e25c779eSMatthew Dillon      bzero(&spp, sizeof(pdu_t));
595e25c779eSMatthew Dillon      p->cmd = ISCSI_LOGOUT_CMD| 0x40;
596e25c779eSMatthew Dillon      p->reason = BIT(7) | 0;
597e25c779eSMatthew Dillon      p->CID = htons(1);
598e25c779eSMatthew Dillon 
599e25c779eSMatthew Dillon      return sendPDU(sess, &spp, handleLogoutResp);
600e25c779eSMatthew Dillon }
601e25c779eSMatthew Dillon 
602e25c779eSMatthew Dillon static trans_t
inLogout(isess_t * sess)603e25c779eSMatthew Dillon inLogout(isess_t *sess)
604e25c779eSMatthew Dillon {
605e25c779eSMatthew Dillon      if(sess->flags & SESS_RECONNECT)
606e25c779eSMatthew Dillon 	  return T18;
607e25c779eSMatthew Dillon      return 0;
608e25c779eSMatthew Dillon }
609e25c779eSMatthew Dillon 
610e25c779eSMatthew Dillon typedef enum {
611e25c779eSMatthew Dillon      S1=1, S2, S3, S4, S5, S6, S7, S8
612e25c779eSMatthew Dillon } state_t;
613e25c779eSMatthew Dillon 
614e25c779eSMatthew Dillon #if 0
615e25c779eSMatthew Dillon       S1: FREE
616e25c779eSMatthew Dillon       S2: XPT_WAIT
617e25c779eSMatthew Dillon       S4: IN_LOGIN
618e25c779eSMatthew Dillon       S5: LOGGED_IN
619e25c779eSMatthew Dillon       S6: IN_LOGOUT
620e25c779eSMatthew Dillon       S7: LOGOUT_REQUESTED
621e25c779eSMatthew Dillon       S8: CLEANUP_WAIT
622e25c779eSMatthew Dillon 
623e25c779eSMatthew Dillon                      -------<-------------+
624e25c779eSMatthew Dillon          +--------->/ S1    \<----+       |
625e25c779eSMatthew Dillon       T13|       +->\       /<-+   \      |
626e25c779eSMatthew Dillon          |      /    ---+---    \   \     |
627e25c779eSMatthew Dillon          |     /        |     T2 \   |    |
628e25c779eSMatthew Dillon          |  T8 |        |T1       |  |    |
629e25c779eSMatthew Dillon          |     |        |        /   |T7  |
630e25c779eSMatthew Dillon          |     |        |       /    |    |
631e25c779eSMatthew Dillon          |     |        |      /     |    |
632e25c779eSMatthew Dillon          |     |        V     /     /     |
633e25c779eSMatthew Dillon          |     |     ------- /     /      |
634e25c779eSMatthew Dillon          |     |    / S2    \     /       |
635e25c779eSMatthew Dillon          |     |    \       /    /        |
636e25c779eSMatthew Dillon          |     |     ---+---    /         |
637e25c779eSMatthew Dillon          |     |        |T4    /          |
638e25c779eSMatthew Dillon          |     |        V     /           | T18
639e25c779eSMatthew Dillon          |     |     ------- /            |
640e25c779eSMatthew Dillon          |     |    / S4    \             |
641e25c779eSMatthew Dillon          |     |    \       /             |
642e25c779eSMatthew Dillon          |     |     ---+---              |         T15
643e25c779eSMatthew Dillon          |     |        |T5      +--------+---------+
644e25c779eSMatthew Dillon          |     |        |       /T16+-----+------+  |
645e25c779eSMatthew Dillon          |     |        |      /   -+-----+--+   |  |
646e25c779eSMatthew Dillon          |     |        |     /   /  S7   \  |T12|  |
647e25c779eSMatthew Dillon          |     |        |    / +->\       /<-+   V  V
648e25c779eSMatthew Dillon          |     |        |   / /    -+-----       -------
649e25c779eSMatthew Dillon          |     |        |  / /T11   |T10        /  S8   \
650e25c779eSMatthew Dillon          |     |        V / /       V  +----+   \       /
651e25c779eSMatthew Dillon          |     |      ---+-+-      ----+--  |    -------
652e25c779eSMatthew Dillon          |     |     / S5    \T9  / S6    \<+    ^
653e25c779eSMatthew Dillon          |     +-----\       /--->\       / T14  |
654e25c779eSMatthew Dillon          |            -------      --+----+------+T17
655e25c779eSMatthew Dillon          +---------------------------+
656e25c779eSMatthew Dillon #endif
657e25c779eSMatthew Dillon 
658e25c779eSMatthew Dillon int
fsm(isc_opt_t * op)659e25c779eSMatthew Dillon fsm(isc_opt_t *op)
660e25c779eSMatthew Dillon {
661e25c779eSMatthew Dillon      state_t	state;
662e25c779eSMatthew Dillon      isess_t	*sess;
663e25c779eSMatthew Dillon 
664e25c779eSMatthew Dillon      if((sess = calloc(1, sizeof(isess_t))) == NULL) {
665e25c779eSMatthew Dillon 	  // boy, is this a bad start ...
666e25c779eSMatthew Dillon 	  fprintf(stderr, "no memory!\n");
667e25c779eSMatthew Dillon 	  return -1;
668e25c779eSMatthew Dillon      }
669e25c779eSMatthew Dillon 
670e25c779eSMatthew Dillon      state = S1;
671e25c779eSMatthew Dillon      sess->op = op;
672e25c779eSMatthew Dillon      sess->fd = -1;
673e25c779eSMatthew Dillon      sess->soc = -1;
674e25c779eSMatthew Dillon      sess->target.address = strdup(op->targetAddress);
675e25c779eSMatthew Dillon      sess->target.port = op->port;
676e25c779eSMatthew Dillon      sess->target.pgt = op->targetPortalGroupTag;
677e25c779eSMatthew Dillon 
678e25c779eSMatthew Dillon      sess->flags = SESS_INITIALLOGIN | SESS_INITIALLOGIN1;
679e25c779eSMatthew Dillon 
680e25c779eSMatthew Dillon      do {
681e25c779eSMatthew Dillon 	  switch(state) {
682e25c779eSMatthew Dillon 	  case S1:
683e25c779eSMatthew Dillon 	       switch(tcpConnect(sess)) {
684e25c779eSMatthew Dillon 	       case T1: state = S2; break;
685e25c779eSMatthew Dillon 	       default: state = S8; break;
686e25c779eSMatthew Dillon 	       }
687e25c779eSMatthew Dillon 	       break;
688e25c779eSMatthew Dillon 
689e25c779eSMatthew Dillon 	  case S2:
690e25c779eSMatthew Dillon 	       switch(startSession(sess)) {
691e25c779eSMatthew Dillon 	       case T2: state = S1; break;
692e25c779eSMatthew Dillon 	       case T4: state = S4; break;
693e25c779eSMatthew Dillon 	       default: state = S8; break;
694e25c779eSMatthew Dillon 	       }
695e25c779eSMatthew Dillon 	       break;
696e25c779eSMatthew Dillon 
697e25c779eSMatthew Dillon 	  case S4:
698e25c779eSMatthew Dillon 	       switch(doLogin(sess)) {
699e25c779eSMatthew Dillon 	       case T7:  state = S1; break;
700e25c779eSMatthew Dillon 	       case T5:  state = S5; break;
701e25c779eSMatthew Dillon 	       default: state = S8; break;
702e25c779eSMatthew Dillon 	       }
703e25c779eSMatthew Dillon 	       break;
704e25c779eSMatthew Dillon 
705e25c779eSMatthew Dillon 	  case S5:
706e25c779eSMatthew Dillon 	       switch(supervise(sess)) {
707e25c779eSMatthew Dillon 	       case T8:  state = S1; break;
708e25c779eSMatthew Dillon 	       case T9:  state = S6; break;
709e25c779eSMatthew Dillon 	       case T11: state = S7; break;
710e25c779eSMatthew Dillon 	       case T15: state = S8; break;
711e25c779eSMatthew Dillon 	       default: state = S8; break;
712e25c779eSMatthew Dillon 	       }
713e25c779eSMatthew Dillon 	       break;
714e25c779eSMatthew Dillon 
715e25c779eSMatthew Dillon 	  case S6:
716e25c779eSMatthew Dillon 	       switch(startLogout(sess)) {
717e25c779eSMatthew Dillon 	       case T13: state = S1; break;
718e25c779eSMatthew Dillon 	       case T14: state = S6; break;
719e25c779eSMatthew Dillon 	       case T16: state = S8; break;
720e25c779eSMatthew Dillon 	       default: state = S8; break;
721e25c779eSMatthew Dillon 	       }
722e25c779eSMatthew Dillon 	       break;
723e25c779eSMatthew Dillon 
724e25c779eSMatthew Dillon 	  case S7:
725e25c779eSMatthew Dillon 	       switch(inLogout(sess)) {
726e25c779eSMatthew Dillon 	       case T18: state = S1; break;
727e25c779eSMatthew Dillon 	       case T10: state = S6; break;
728e25c779eSMatthew Dillon 	       case T12: state = S7; break;
729e25c779eSMatthew Dillon 	       case T16: state = S8; break;
730e25c779eSMatthew Dillon 	       default: state = S8; break;
731e25c779eSMatthew Dillon 	       }
732e25c779eSMatthew Dillon 	       break;
733e25c779eSMatthew Dillon 
734e25c779eSMatthew Dillon 	  case S8:
735e25c779eSMatthew Dillon 	       // maybe do some clean up?
736e25c779eSMatthew Dillon 	       syslog(LOG_INFO, "terminated");
737e25c779eSMatthew Dillon 	       return 0;
738e25c779eSMatthew Dillon 	  default:
739e25c779eSMatthew Dillon 	       syslog(LOG_INFO, "unknown state %d", state);
740e25c779eSMatthew Dillon 	       return 0;
741e25c779eSMatthew Dillon 	  }
742e25c779eSMatthew Dillon      } while(1);
743e25c779eSMatthew Dillon }
744