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 67static int ou_refcnt = 0; 68/* 69 | function for freeing external storage for mbuf 70 */ 71static void 72ext_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 83int 84isc_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 */ 184int 185isc_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 */ 315static __inline int 316so_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 */ 367static int 368so_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 */ 552static int 553so_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 */ 594static void 595isc_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 657void 658isc_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 689void 690isc_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