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 int 72ext_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 84int 85isc_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 */ 185int 186isc_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 */ 316static __inline int 317so_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 */ 368static int 369so_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 */ 553static int 554so_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 */ 595static void 596isc_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 658void 659isc_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 690void 691isc_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} 703