1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2005-2010 Daniel Braniss <danny@cs.huji.ac.il>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29 /*
30 | $Id: isc_soc.c 998 2009-12-20 10:32:45Z danny $
31 */
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include "opt_iscsi_initiator.h"
36
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/conf.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/ctype.h>
43 #include <sys/errno.h>
44 #include <sys/sysctl.h>
45 #include <sys/file.h>
46 #include <sys/uio.h>
47 #include <sys/socketvar.h>
48 #include <sys/socket.h>
49 #include <sys/protosw.h>
50 #include <sys/proc.h>
51 #include <sys/ioccom.h>
52 #include <sys/queue.h>
53 #include <sys/kthread.h>
54 #include <sys/syslog.h>
55 #include <sys/mbuf.h>
56 #include <sys/user.h>
57 #include <vm/uma.h>
58
59 #include <cam/cam.h>
60 #include <cam/cam_ccb.h>
61
62 #include <dev/iscsi_initiator/iscsi.h>
63 #include <dev/iscsi_initiator/iscsivar.h>
64
65 #ifndef NO_USE_MBUF
66 #define USE_MBUF
67 #endif
68
69 #ifdef USE_MBUF
70 static int ou_refcnt = 0;
71 /*
72 | function for freeing external storage for mbuf
73 */
74 static void
75 ext_free(struct mbuf *m)
76 {
77 pduq_t *pq = m->m_ext.ext_arg1;
78
79 if(pq->buf != NULL) {
80 debug(3, "ou_refcnt=%d a=%p b=%p",
81 ou_refcnt, m->m_ext.ext_buf, pq->buf);
82 free(pq->buf, M_ISCSIBUF);
83 pq->buf = NULL;
84 }
85 }
86
87 int
88 isc_sendPDU(isc_session_t *sp, pduq_t *pq)
89 {
90 struct mbuf *mh, **mp;
91 pdu_t *pp = &pq->pdu;
92 int len, error;
93
94 debug_called(8);
95 /*
96 | mbuf for the iSCSI header
97 */
98 MGETHDR(mh, M_WAITOK, MT_DATA);
99 mh->m_pkthdr.rcvif = NULL;
100 mh->m_next = NULL;
101 mh->m_len = sizeof(union ipdu_u);
102
103 if(ISOK2DIG(sp->hdrDigest, pp)) {
104 pp->hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0);
105 mh->m_len += sizeof(pp->hdr_dig);
106 if(pp->ahs_len) {
107 debug(2, "ahs_len=%d", pp->ahs_len);
108 pp->hdr_dig = sp->hdrDigest(&pp->ahs_addr, pp->ahs_len, pp->hdr_dig);
109 }
110 debug(3, "pp->hdr_dig=%04x", htonl(pp->hdr_dig));
111 }
112 if(pp->ahs_len) {
113 /*
114 | Add any AHS to the iSCSI hdr mbuf
115 */
116 if((mh->m_len + pp->ahs_len) < MHLEN) {
117 M_ALIGN(mh, mh->m_len + pp->ahs_len);
118 bcopy(&pp->ipdu, mh->m_data, mh->m_len);
119 bcopy(pp->ahs_addr, mh->m_data + mh->m_len, pp->ahs_len);
120 mh->m_len += pp->ahs_len;
121 }
122 else
123 panic("len AHS=%d too big, not impleneted yet", pp->ahs_len);
124 }
125 else {
126 M_ALIGN(mh, mh->m_len);
127 bcopy(&pp->ipdu, mh->m_data, mh->m_len);
128 }
129 mh->m_pkthdr.len = mh->m_len;
130 mp = &mh->m_next;
131 if(pp->ds_len && pq->pdu.ds_addr) {
132 struct mbuf *md;
133 int off = 0;
134
135 len = pp->ds_len;
136 while(len > 0) {
137 int l;
138
139 MGET(md, M_WAITOK, MT_DATA);
140 md->m_ext.ext_cnt = &ou_refcnt;
141 l = min(MCLBYTES, len);
142 debug(4, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l);
143 m_extadd(md, pp->ds_addr + off, l, ext_free, pq, NULL, 0,
144 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 aligned
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 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 }
Cache object: c682ac49d8e30a2ea0385c8790c5c766
|