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