xref: /NextBSD/sys/dev/iscsi_initiator/isc_soc.c (revision 287e3b14e9552995def1802ec9c5034f4adf28ec)
1 /*-
2  * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 /*
28  | $Id: isc_soc.c 998 2009-12-20 10:32:45Z danny $
29  */
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include "opt_iscsi_initiator.h"
34 
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/conf.h>
38 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/ctype.h>
41 #include <sys/errno.h>
42 #include <sys/sysctl.h>
43 #include <sys/file.h>
44 #include <sys/uio.h>
45 #include <sys/socketvar.h>
46 #include <sys/socket.h>
47 #include <sys/protosw.h>
48 #include <sys/proc.h>
49 #include <sys/ioccom.h>
50 #include <sys/queue.h>
51 #include <sys/kthread.h>
52 #include <sys/syslog.h>
53 #include <sys/mbuf.h>
54 #include <sys/user.h>
55 
56 #include <cam/cam.h>
57 #include <cam/cam_ccb.h>
58 
59 #include <dev/iscsi_initiator/iscsi.h>
60 #include <dev/iscsi_initiator/iscsivar.h>
61 
62 #ifndef NO_USE_MBUF
63 #define USE_MBUF
64 #endif
65 
66 #ifdef USE_MBUF
67 static int ou_refcnt = 0;
68 /*
69  | function for freeing external storage for mbuf
70  */
71 static void
ext_free(struct mbuf * m,void * a,void * b)72 ext_free(struct mbuf *m, void *a, void *b)
73 {
74      pduq_t *pq = b;
75 
76      if(pq->buf != NULL) {
77 	  debug(3, "ou_refcnt=%d a=%p b=%p", ou_refcnt, a, pq->buf);
78 	  free(pq->buf, M_ISCSIBUF);
79 	  pq->buf = NULL;
80      }
81 }
82 
83 int
isc_sendPDU(isc_session_t * sp,pduq_t * pq)84 isc_sendPDU(isc_session_t *sp, pduq_t *pq)
85 {
86      struct mbuf *mh, **mp;
87      pdu_t	*pp = &pq->pdu;
88      int	len, error;
89 
90      debug_called(8);
91      /*
92       | mbuf for the iSCSI header
93       */
94      MGETHDR(mh, M_WAITOK, MT_DATA);
95      mh->m_pkthdr.rcvif = NULL;
96      mh->m_next = NULL;
97      mh->m_len = sizeof(union ipdu_u);
98 
99      if(ISOK2DIG(sp->hdrDigest, pp)) {
100 	  pp->hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
101 	  mh->m_len += sizeof(pp->hdr_dig);
102 	  if(pp->ahs_len) {
103 	       debug(2, "ahs_len=%d", pp->ahs_len);
104 	       pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
105 	  }
106 	  debug(3, "pp->hdr_dig=%04x", htonl(pp->hdr_dig));
107      }
108      if(pp->ahs_len) {
109           /*
110 	   | Add any AHS to the iSCSI hdr mbuf
111 	   */
112 	  if((mh->m_len + pp->ahs_len) < MHLEN) {
113 	       M_ALIGN(mh, mh->m_len + pp->ahs_len);
114 	       bcopy(&pp->ipdu, mh->m_data, mh->m_len);
115 	       bcopy(pp->ahs_addr, mh->m_data + mh->m_len, pp->ahs_len);
116 	       mh->m_len += pp->ahs_len;
117 	  }
118 	  else
119 	       panic("len AHS=%d too big, not impleneted yet", pp->ahs_len);
120      }
121      else {
122 	  M_ALIGN(mh, mh->m_len);
123 	  bcopy(&pp->ipdu, mh->m_data, mh->m_len);
124      }
125      mh->m_pkthdr.len = mh->m_len;
126      mp = &mh->m_next;
127      if(pp->ds_len && pq->pdu.ds_addr) {
128           struct mbuf *md;
129           int	off = 0;
130 
131           len = pp->ds_len;
132           while(len > 0) {
133 	       int l;
134 
135 	       MGET(md, M_WAITOK, MT_DATA);
136 	       md->m_ext.ext_cnt = &ou_refcnt;
137 	       l = min(MCLBYTES, len);
138 	       debug(4, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
139 	       MEXTADD(md, pp->ds_addr + off, l, ext_free,
140 #if __FreeBSD_version >= 800000
141 		       pp->ds_addr + off,
142 #endif
143 		       pq, 0, EXT_EXTREF);
144 	       md->m_len = l;
145 	       md->m_next = NULL;
146 	       mh->m_pkthdr.len += l;
147 	       *mp = md;
148 	       mp = &md->m_next;
149 	       len -= l;
150 	       off += l;
151           }
152 	  if(((pp->ds_len & 03) != 0) || ISOK2DIG(sp->dataDigest, pp)) {
153 	       MGET(md, M_WAITOK, MT_DATA);
154 	       if(pp->ds_len & 03)
155 		    len = 4 - (pp->ds_len & 03);
156 	       else
157 		    len = 0;
158 	       md->m_len = len;
159 	       if(ISOK2DIG(sp->dataDigest, pp))
160 		    md->m_len += sizeof(pp->ds_dig);
161 	       M_ALIGN(md, md->m_len);
162 	       if(ISOK2DIG(sp->dataDigest, pp)) {
163 		    pp->ds_dig = sp->dataDigest(pp->ds_addr, pp->ds_len, 0);
164 		    if(len) {
165 			 bzero(md->m_data, len); // RFC says SHOULD be 0
166 			 pp->ds_dig = sp->dataDigest(md->m_data, len, pp->ds_dig);
167 		    }
168 		    bcopy(&pp->ds_dig, md->m_data+len, sizeof(pp->ds_dig));
169 	       }
170 	       md->m_next = NULL;
171 	       mh->m_pkthdr.len += md->m_len;
172 	       *mp = md;
173 	  }
174      }
175      if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) {
176 	  sdebug(2, "error=%d", error);
177 	  return error;
178      }
179      sp->stats.nsent++;
180      getbintime(&sp->stats.t_sent);
181      return 0;
182 }
183 #else /* NO_USE_MBUF */
184 int
isc_sendPDU(isc_session_t * sp,pduq_t * pq)185 isc_sendPDU(isc_session_t *sp, pduq_t *pq)
186 {
187      struct uio *uio = &pq->uio;
188      struct iovec *iv;
189      pdu_t	*pp = &pq->pdu;
190      int	len, error;
191 
192      debug_called(8);
193 
194      bzero(uio, sizeof(struct uio));
195      uio->uio_rw = UIO_WRITE;
196      uio->uio_segflg = UIO_SYSSPACE;
197      uio->uio_td = sp->td;
198      uio->uio_iov = iv = pq->iov;
199 
200      iv->iov_base = &pp->ipdu;
201      iv->iov_len = sizeof(union ipdu_u);
202      uio->uio_resid = iv->iov_len;
203      iv++;
204      if(ISOK2DIG(sp->hdrDigest, pp))
205 	  pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
206      if(pp->ahs_len) {
207 	  iv->iov_base = pp->ahs_addr;
208 	  iv->iov_len = pp->ahs_len;
209 	  uio->uio_resid += iv->iov_len;
210 	  iv++;
211 	  if(ISOK2DIG(sp->hdrDigest, pp))
212 	       pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
213      }
214      if(ISOK2DIG(sp->hdrDigest, pp)) {
215 	  debug(3, "hdr_dig=%04x", htonl(pp->hdr_dig));
216 	  iv->iov_base = &pp->hdr_dig;
217 	  iv->iov_len = sizeof(int);
218 	  uio->uio_resid += iv->iov_len ;
219 	  iv++;
220      }
221      if(pq->pdu.ds_addr &&  pp->ds_len) {
222 	  iv->iov_base = pp->ds_addr;
223 	  iv->iov_len = pp->ds_len;
224 	  while(iv->iov_len & 03) // the specs say it must be int alligned
225 	       iv->iov_len++;
226 	  uio->uio_resid += iv->iov_len ;
227 	  iv++;
228 	  if(ISOK2DIG(sp->dataDigest, pp)) {
229 	       pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0);
230 	       iv->iov_base = &pp->ds_dig;
231 	       iv->iov_len = sizeof(pp->ds_dig);
232 	       uio->uio_resid += iv->iov_len ;
233 	       iv++;
234 	  }
235      }
236      uio->uio_iovcnt = iv - pq->iov;
237      sdebug(4, "pq->len=%d uio->uio_resid=%d  uio->uio_iovcnt=%d", pq->len,
238 	    uio->uio_resid,
239 	    uio->uio_iovcnt);
240 
241      sdebug(4, "opcode=%x iovcnt=%d uio_resid=%d itt=%x",
242 	    pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid,
243 	    ntohl(pp->ipdu.bhs.itt));
244      sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p",
245 	    sp, sp->soc, uio, sp->td);
246      do {
247 	  len = uio->uio_resid;
248 	  error = sosend(sp->soc, NULL, uio, 0, 0, 0, sp->td);
249 	  if(uio->uio_resid == 0 || error || len == uio->uio_resid) {
250 	       if(uio->uio_resid) {
251 		    sdebug(2, "uio->uio_resid=%d uio->uio_iovcnt=%d error=%d len=%d",
252 			   uio->uio_resid, uio->uio_iovcnt, error, len);
253 		    if(error == 0)
254 			 error = EAGAIN; // 35
255 	       }
256 	       break;
257 	  }
258 	  /*
259 	   | XXX: untested code
260 	   */
261 	  sdebug(1, "uio->uio_resid=%d uio->uio_iovcnt=%d",
262 		 uio->uio_resid, uio->uio_iovcnt);
263 	  iv = uio->uio_iov;
264 	  len -= uio->uio_resid;
265 	  while(uio->uio_iovcnt > 0) {
266 	       if(iv->iov_len > len) {
267 		    caddr_t bp = (caddr_t)iv->iov_base;
268 
269 		    iv->iov_len -= len;
270 		    iv->iov_base = (void *)&bp[len];
271 		    break;
272 	       }
273 	       len -= iv->iov_len;
274 	       uio->uio_iovcnt--;
275 	       uio->uio_iov++;
276 	       iv++;
277 	  }
278      } while(uio->uio_resid);
279 
280      if(error == 0) {
281 	  sp->stats.nsent++;
282 	  getbintime(&sp->stats.t_sent);
283      }
284 
285      return error;
286 }
287 #endif /* USE_MBUF */
288 
289 /*
290  | wait till a PDU header is received
291  | from the socket.
292  */
293 /*
294    The format of the BHS is:
295 
296    Byte/     0       |       1       |       2       |       3       |
297       /              |               |               |               |
298      |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|
299      +---------------+---------------+---------------+---------------+
300     0|.|I| Opcode    |F|  Opcode-specific fields                     |
301      +---------------+---------------+---------------+---------------+
302     4|TotalAHSLength | DataSegmentLength                             |
303      +---------------+---------------+---------------+---------------+
304     8| LUN or Opcode-specific fields                                 |
305      +                                                               +
306    12|                                                               |
307      +---------------+---------------+---------------+---------------+
308    16| Initiator Task Tag                                            |
309      +---------------+---------------+---------------+---------------+
310    20/ Opcode-specific fields                                        /
311     +/                                                               /
312      +---------------+---------------+---------------+---------------+
313    48
314  */
315 static __inline int
so_getbhs(isc_session_t * sp)316 so_getbhs(isc_session_t *sp)
317 {
318      bhs_t *bhs		= &sp->bhs;
319      struct uio		*uio = &sp->uio;
320      struct iovec	*iov = &sp->iov;
321      int		error, flags;
322 
323      debug_called(8);
324 
325      iov->iov_base	= bhs;
326      iov->iov_len	= sizeof(bhs_t);
327 
328      uio->uio_iov	= iov;
329      uio->uio_iovcnt	= 1;
330      uio->uio_rw	= UIO_READ;
331      uio->uio_segflg	= UIO_SYSSPACE;
332      uio->uio_td	= curthread; // why ...
333      uio->uio_resid	= sizeof(bhs_t);
334 
335      flags = MSG_WAITALL;
336      error = soreceive(sp->soc, NULL, uio, 0, 0, &flags);
337 
338      if(error)
339 	  debug(2,
340 #if __FreeBSD_version > 800000
341 		"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd",
342 #else
343 		"error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd",
344 #endif
345 		error,
346 		sp->soc->so_error, uio->uio_resid, iov->iov_len);
347      if(!error && (uio->uio_resid > 0)) {
348 	  error = EPIPE; // was EAGAIN
349 	  debug(2,
350 #if __FreeBSD_version > 800000
351 		"error=%d so_error=%d uio->uio_resid=%zd iov.iov_len=%zd so_state=%x",
352 #else
353 		"error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd so_state=%x",
354 #endif
355 		error,
356 		sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state);
357      }
358      return error;
359 }
360 
361 /*
362  | so_recv gets called when
363  | an iSCSI header has been received.
364  | Note: the designers had no intentions
365  |       in making programmer's life easy.
366  */
367 static int
so_recv(isc_session_t * sp,pduq_t * pq)368 so_recv(isc_session_t *sp, pduq_t *pq)
369 {
370      sn_t		*sn = &sp->sn;
371      struct uio		*uio = &pq->uio;
372      pdu_t		*pp = &pq->pdu;
373      bhs_t		*bhs = &pp->ipdu.bhs;
374      struct iovec	*iov = pq->iov;
375      int		error;
376      u_int		len;
377      u_int		max, exp;
378      int		flags = MSG_WAITALL;
379 
380      debug_called(8);
381      /*
382       | now calculate how much data should be in the buffer
383       */
384      uio->uio_iov	= iov;
385      uio->uio_iovcnt	= 0;
386      len = 0;
387      if(bhs->AHSLength) {
388 	  debug(2, "bhs->AHSLength=%d", bhs->AHSLength);
389 	  pp->ahs_len = bhs->AHSLength * 4;
390 	  len += pp->ahs_len;
391 	  pp->ahs_addr = malloc(pp->ahs_len, M_TEMP, M_WAITOK); // XXX: could get stuck here
392 	  iov->iov_base = pp->ahs_addr;
393 	  iov->iov_len = pp->ahs_len;
394 	  uio->uio_iovcnt++;
395 	  iov++;
396      }
397      if(ISOK2DIG(sp->hdrDigest, pp)) {
398 	  len += sizeof(pp->hdr_dig);
399 	  iov->iov_base = &pp->hdr_dig;
400 	  iov->iov_len = sizeof(pp->hdr_dig);
401 	  uio->uio_iovcnt++;
402      }
403      if(len) {
404 	  uio->uio_rw		= UIO_READ;
405 	  uio->uio_segflg	= UIO_SYSSPACE;
406 	  uio->uio_resid	= len;
407 	  uio->uio_td		= sp->td; // why ...
408 	  error = soreceive(sp->soc, NULL, uio, NULL, NULL, &flags);
409 	  //if(error == EAGAIN)
410 	  // XXX: this needs work! it hangs iscontrol
411 	  if(error || uio->uio_resid) {
412 	       debug(2,
413 #if __FreeBSD_version > 800000
414 		     "len=%d error=%d uio->uio_resid=%zd",
415 #else
416 		     "len=%d error=%d uio->uio_resid=%d",
417 #endif
418 		     len, error, uio->uio_resid);
419 	       goto out;
420 	  }
421 	  if(ISOK2DIG(sp->hdrDigest, pp)) {
422 	       bhs_t	*bhs;
423 	       u_int	digest;
424 
425 	       bhs = (bhs_t *)&pp->ipdu;
426 	       digest = sp->hdrDigest(bhs, sizeof(bhs_t), 0);
427 	       if(pp->ahs_len)
428 		    digest = sp->hdrDigest(pp->ahs_addr, pp->ahs_len, digest);
429 	       if(pp->hdr_dig != digest) {
430 		    debug(2, "bad header digest: received=%x calculated=%x", pp->hdr_dig, digest);
431 		    // XXX: now what?
432 		    error = EIO;
433 		    goto out;
434 	       }
435 	  }
436 	  if(pp->ahs_len) {
437 	       debug(2, "ahs len=%x type=%x spec=%x",
438 		     pp->ahs_addr->len, pp->ahs_addr->type, pp->ahs_addr->spec);
439 	       // XXX: till I figure out what to do with this
440 	       free(pp->ahs_addr, M_TEMP);
441 	  }
442 	  pq->len += len; // XXX: who needs this?
443 	  bzero(uio, sizeof(struct uio));
444 	  len = 0;
445      }
446 
447      if(bhs->DSLength) {
448 	  len = bhs->DSLength;
449 #if BYTE_ORDER == LITTLE_ENDIAN
450 	  len = ((len & 0x00ff0000) >> 16)
451 	       | (len & 0x0000ff00)
452 	       | ((len & 0x000000ff) << 16);
453 #endif
454 	  pp->ds_len = len;
455 	  if((sp->opt.maxRecvDataSegmentLength > 0) && (len > sp->opt.maxRecvDataSegmentLength)) {
456 	       xdebug("impossible PDU length(%d) opt.maxRecvDataSegmentLength=%d",
457 		      len, sp->opt.maxRecvDataSegmentLength);
458 	       log(LOG_ERR,
459 		   "so_recv: impossible PDU length(%d) from iSCSI %s/%s\n",
460 		   len, sp->opt.targetAddress, sp->opt.targetName);
461 	       /*
462 		| XXX: this will really screwup the stream.
463 		| should clear up the buffer till a valid header
464 		| is found, or just close connection ...
465 		| should read the RFC.
466 	        */
467 	       error = E2BIG;
468 	       goto out;
469 	  }
470 	  while(len & 03)
471 	       len++;
472 	  if(ISOK2DIG(sp->dataDigest, pp))
473 	       len += 4;
474 	  uio->uio_resid = len;
475 	  uio->uio_td = sp->td; // why ...
476 	  pq->len += len; // XXX: do we need this?
477 	  error = soreceive(sp->soc, NULL, uio, &pq->mp, NULL, &flags);
478 	  //if(error == EAGAIN)
479 	  // XXX: this needs work! it hangs iscontrol
480 	  if(error || uio->uio_resid)
481 	       goto out;
482           if(ISOK2DIG(sp->dataDigest, pp)) {
483 	       struct mbuf *m;
484 	       u_int    digest, ds_len, cnt;
485 
486 	       // get the received digest
487 	       m_copydata(pq->mp,
488 			  len - sizeof(pp->ds_dig),
489 			  sizeof(pp->ds_dig),
490 			  (caddr_t)&pp->ds_dig);
491 	       // calculate all mbufs
492 	       digest = 0;
493 	       ds_len = len - sizeof(pp->ds_dig);
494 	       for(m = pq->mp; m != NULL; m = m->m_next) {
495 		    cnt = MIN(ds_len, m->m_len);
496 		    digest = sp->dataDigest(mtod(m, char *), cnt, digest);
497 		    ds_len -= cnt;
498 		    if(ds_len == 0)
499 			 break;
500 	       }
501 	       if(digest != pp->ds_dig) {
502 		    sdebug(1, "bad data digest: received=%x calculated=%x", pp->ds_dig, digest);
503 		    error = EIO; // XXX: find a better error
504 		    goto out;
505 	       }
506 	       KASSERT(ds_len == 0, ("ds_len not zero"));
507 	  }
508      }
509      sdebug(6, "len=%d] opcode=0x%x ahs_len=0x%x ds_len=0x%x",
510 	    pq->len, bhs->opcode, pp->ahs_len, pp->ds_len);
511 
512      max = ntohl(bhs->MaxCmdSN);
513      exp = ntohl(bhs->ExpStSN);
514      if(max < exp - 1 &&
515 	max > exp - _MAXINCR) {
516 	  sdebug(2,  "bad cmd window size");
517 	  error = EIO; // XXX: for now;
518 	  goto out; // error
519      }
520      if(SNA_GT(max, sn->maxCmd))
521 	  sn->maxCmd = max;
522      if(SNA_GT(exp, sn->expCmd))
523 	  sn->expCmd = exp;
524      /*
525       | remove from the holding queue packets
526       | that have been acked and don't need
527       | further processing.
528       */
529      i_acked_hld(sp, NULL);
530 
531      sp->cws = sn->maxCmd - sn->expCmd + 1;
532 
533      return 0;
534 
535  out:
536      // XXX: need some work here
537      if(pp->ahs_len) {
538 	  // XXX: till I figure out what to do with this
539 	  free(pp->ahs_addr, M_TEMP);
540      }
541      xdebug("have a problem, error=%d", error);
542      pdu_free(sp->isc, pq);
543      if(!error && uio->uio_resid > 0)
544 	  error = EPIPE;
545      return error;
546 }
547 
548 /*
549  | wait for something to arrive.
550  | and if the pdu is without errors, process it.
551  */
552 static int
so_input(isc_session_t * sp)553 so_input(isc_session_t *sp)
554 {
555      pduq_t		*pq;
556      int		error;
557 
558      debug_called(8);
559      /*
560       | first read in the iSCSI header
561       */
562      error = so_getbhs(sp);
563      if(error == 0) {
564 	  /*
565 	   | now read the rest.
566 	   */
567 	  pq = pdu_alloc(sp->isc, M_NOWAIT);
568 	  if(pq == NULL) { // XXX: might cause a deadlock ...
569 	       debug(2, "out of pdus, wait");
570 	       pq = pdu_alloc(sp->isc, M_WAITOK);  // OK to WAIT
571 	  }
572 	  pq->pdu.ipdu.bhs = sp->bhs;
573 	  pq->len = sizeof(bhs_t);	// so far only the header was read
574 	  error = so_recv(sp, pq);
575 	  if(error != 0) {
576 	       error += 0x800; // XXX: just to see the error.
577 	       // terminal error
578 	       // XXX: close connection and exit
579 	  }
580 	  else {
581 	       sp->stats.nrecv++;
582 	       getbintime(&sp->stats.t_recv);
583 	       ism_recv(sp, pq);
584 	  }
585      }
586      return error;
587 }
588 
589 /*
590  | one per active (connected) session.
591  | this thread is responsible for reading
592  | in packets from the target.
593  */
594 static void
isc_in(void * vp)595 isc_in(void *vp)
596 {
597      isc_session_t	*sp = (isc_session_t *)vp;
598      struct socket	*so = sp->soc;
599      int		error;
600 
601      debug_called(8);
602 
603      sp->flags |= ISC_CON_RUNNING;
604      error = 0;
605      while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) {
606 	  // XXX: hunting ...
607 	  if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) {
608 	       debug(2, "sp->soc=%p", sp->soc);
609 	       break;
610 	  }
611 	  error = so_input(sp);
612 	  if(error == 0) {
613 	       mtx_lock(&sp->io_mtx);
614 	       if(sp->flags & ISC_OWAITING) {
615 		    wakeup(&sp->flags);
616 	       }
617 	       mtx_unlock(&sp->io_mtx);
618 	  } else if(error == EPIPE) {
619 	       break;
620 	  }
621 	  else if(error == EAGAIN) {
622 	       if(so->so_state & SS_ISCONNECTED)
623 		    // there seems to be a problem in 6.0 ...
624 		    tsleep(sp, PRIBIO, "isc_soc", 2*hz);
625 	  }
626      }
627      sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d proc=%p",
628 	    sp->flags, so->so_count, so->so_state, error, sp->proc);
629      if((sp->proc != NULL) && sp->signal) {
630 	  PROC_LOCK(sp->proc);
631 	  kern_psignal(sp->proc, sp->signal);
632 	  PROC_UNLOCK(sp->proc);
633 	  sp->flags |= ISC_SIGNALED;
634 	  sdebug(2, "pid=%d signaled(%d)", sp->proc->p_pid, sp->signal);
635      }
636      else {
637 	  // we have to do something ourselves
638 	  // like closing this session ...
639      }
640      /*
641       | we've been terminated
642       */
643      // do we need this mutex ...?
644      mtx_lock(&sp->io_mtx);
645      sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP);
646      wakeup(&sp->soc);
647      mtx_unlock(&sp->io_mtx);
648 
649      sdebug(2, "dropped ISC_CON_RUNNING");
650 #if __FreeBSD_version >= 800000
651      kproc_exit(0);
652 #else
653      kthread_exit(0);
654 #endif
655 }
656 
657 void
isc_stop_receiver(isc_session_t * sp)658 isc_stop_receiver(isc_session_t *sp)
659 {
660      int	n;
661 
662      debug_called(8);
663      sdebug(3, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0);
664      mtx_lock(&sp->io_mtx);
665      sp->flags &= ~ISC_LINK_UP;
666      msleep(&sp->soc, &sp->io_mtx, PRIBIO|PDROP, "isc_stpc", 5*hz);
667 
668      soshutdown(sp->soc, SHUT_RD);
669 
670      mtx_lock(&sp->io_mtx);
671      sdebug(3, "soshutdown");
672      sp->flags &= ~ISC_CON_RUN;
673      n = 2;
674      while(n-- && (sp->flags & ISC_CON_RUNNING)) {
675 	  sdebug(3, "waiting n=%d... flags=%x", n, sp->flags);
676 	  msleep(&sp->soc, &sp->io_mtx, PRIBIO, "isc_stpc", 5*hz);
677      }
678      mtx_unlock(&sp->io_mtx);
679 
680      if(sp->fp != NULL)
681 	  fdrop(sp->fp, sp->td);
682      fputsock(sp->soc);
683      sp->soc = NULL;
684      sp->fp = NULL;
685 
686      sdebug(3, "done");
687 }
688 
689 void
isc_start_receiver(isc_session_t * sp)690 isc_start_receiver(isc_session_t *sp)
691 {
692      debug_called(8);
693 
694      sp->flags |= ISC_CON_RUN | ISC_LINK_UP;
695 #if __FreeBSD_version >= 800000
696      kproc_create
697 #else
698      kthread_create
699 #endif
700 	  (isc_in, sp, &sp->soc_proc, 0, 0, "isc_in %d", sp->sid);
701 }
702