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