]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/iscsi/initiator/isc_soc.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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 void
72 ext_free(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
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_TRYWAIT, 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                MH_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           MH_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_TRYWAIT, MT_DATA);
136                md->m_ext.ref_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_TRYWAIT, 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
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
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
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
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
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
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
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 }