]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netat/adsp_Close.c
c1514caca1c5f3b14f88a61de0dd737225d5299c
2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 * Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
32 * All Rights Reserved.
36 * From Mike Shoemaker v01.16 06/29/90 mbs
40 * 06/29/95 - Modified to handle flow control for writing (Tuyen Nguyen)
41 * Modified for MP, 1996 by Tuyen Nguyen
42 * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
45 #include <sys/errno.h>
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <machine/spl.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
52 #include <sys/filedesc.h>
53 #include <sys/fcntl.h>
55 #include <sys/socket.h>
56 #include <sys/socketvar.h>
59 #include <netat/sysglue.h>
60 #include <netat/appletalk.h>
61 #include <netat/ddp.h>
62 #include <netat/at_pcb.h>
63 #include <netat/debug.h>
64 #include <netat/adsp.h>
65 #include <netat/adsp_internal.h>
67 extern atlock_t adspall_lock
;
69 static void qRemove(CCBPtr
, CCBPtr
);
75 * Check to see if it is OK to close this connection cleanly.
80 * True if no outstanding transactions and we can close cleanly
82 int CheckOkToClose(sp
) /* (CCBPtr sp) */
86 if (sp
->sData
) /* Outstanding data ? */
89 if (sp
->sapb
) /* Outstanding send attention ? */
92 if (sp
->frpb
) /* Outstanding forward reset ? */
102 * Must be OK to close
104 sp
->sendCtl
|= B_CTL_CLOSE
; /* So, need to send close advice */
107 return 1; /* It's OK to close */
114 * Given the address of the head of a queue of DSP parameter blocks, zero
115 * the queue, and complete each item on the queue with the given result
119 * qhead Address of ptr to first queue element
120 * code The result code
124 int CompleteQueue(qhead
, code
) /* (DSPPBPtr FPTR qhead, OSErr code) */
125 struct adspcmd
**qhead
;
128 register struct adspcmd
*p
;
129 register struct adspcmd
*n
;
130 register gref_t
*gref
;
131 register int total
= 0;
135 n
= *qhead
; /* Get first item */
136 *qhead
= 0; /* Zero out the queue */
140 sp
= (CCBPtr
)gbuf_rptr(((gbuf_t
*)gref
->info
));
141 atalk_flush(sp
->gref
);
142 ATDISABLE(s
, sp
->lock
);
146 while (p
= n
) { /* while items left */
147 n
= (struct adspcmd
*)(p
->qLink
); /* Save next guy */
150 completepb(sp
, p
); /* complete the copy of the request */
156 ATENABLE(s
, sp
->lock
);
163 * Called from do close to free up the user's CCB. So, we remove the
164 * CCB from the list of CCB's.
168 * pb a remove param block to complete when done
173 void RemoveCCB(sp
, pb
) /* (CCBPtr sp, DSPPBPtr pb) */
182 * Unlink CCB from list
184 qRemove((CCB
*)AT_ADSP_STREAMS
, sp
); /* remove sp from active streams queue */
188 if (pb
->ioc
) /* is this a current or queued request */
189 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* current */
191 completepb(sp
, pb
); /* queued */
194 if (sp
->opb
&& (pb
!= sp
->opb
)) { /* if the pb requested is not the */
195 pb
= sp
->opb
; /* waiting open pb, complete it too */
205 if (gref
->info
== (char *)sp
->sp_mp
) { /* queue head is still valid */
208 if ((skt
= sp
->localSocket
) != 0) {
209 if (adspDeassignSocket(sp
) == 0)
210 ddp_notify_nbp(skt
, sp
->pid
, DDP_ADSP
);
214 gbuf_freem((gbuf_t
*)gref
->info
); /* free the CCB */
218 gbuf_freem(sp
->sp_mp
); /* our head is already gone, be sure
219 * to release our resources too */
231 * Complete all outstanding transactions.
233 total
= CompleteQueue(&sp
->sapb
, err
); /* Abort outstanding send attentions */
234 CompleteQueue(&sp
->frpb
, err
); /* Abort outstanding forward resets */
236 if (sp
->sbuf_mb
) { /* clear the send queue */
237 gbuf_freel(sp
->sbuf_mb
);
242 gbuf_freem(sp
->csbuf_mb
);
253 * Called from several places (probe timeout, recv close advice,
254 * dspRemove, etc.) to change state of connection to closed and
255 * complete all outstanding I/O.
257 * Will also remove the CCB if there is a dsp remove pending.
264 void DoClose(sp
, err
, force_abort
) /* (CCBPtr sp, OSErr err) */
268 register struct adspcmd
*pb
, *np
;
272 dPrintf(D_M_ADSP
, D_L_TRACE
, ("DoClose: pid=%d,e=%d,a=%d,s=%d,r=%d\n",
273 sp
->pid
, err
, force_abort
, sp
->localSocket
, sp
->removing
));
274 sp
->userFlags
|= eClosed
; /* Set flag */
276 sp
->openState
= O_STATE_NOTHING
;
279 * Clean up any timer elements
281 RemoveTimerElem(&adspGlobal
.slowTimers
, &sp
->ProbeTimer
);
282 RemoveTimerElem(&adspGlobal
.fastTimers
, &sp
->FlushTimer
);
283 RemoveTimerElem(&adspGlobal
.fastTimers
, &sp
->RetryTimer
);
284 RemoveTimerElem(&adspGlobal
.fastTimers
, &sp
->AttnTimer
);
285 RemoveTimerElem(&adspGlobal
.fastTimers
, &sp
->ResetTimer
);
287 aborted_count
= AbortIO(sp
, err
);
288 np
= sp
->opb
; /* Get list of close/removes to complete */
289 sp
->opb
= 0; /* set this list null */
291 while (pb
= np
) { /* Handle all of the close/remove param blks */
292 np
= (struct adspcmd
*)pb
->qLink
; /* Get next guy (if any) */
297 if (sp
->removing
&& (force_abort
>= 0)) { /* Abort outstanding receives */
298 aborted_count
+= CompleteQueue(&sp
->rpb
, err
);
300 if (sp
->deferred_mb
) {
301 gbuf_freel(sp
->deferred_mb
);
305 gbuf_freem(sp
->attn_mb
);
308 if (sp
->rbuf_mb
) { /* clear the rcv queue */
309 gbuf_freem(sp
->rbuf_mb
);
313 gbuf_freem(sp
->crbuf_mb
);
318 /* if our connection has been timed out */
319 /* and the user wasn't notified of the TearDown */
320 /* because of pending requests on this socket */
321 /* then fake a read completion to force the notification */
323 if (force_abort
&& aborted_count
== 0) {
324 if (mp
= gbuf_alloc(sizeof(struct adspcmd
), PRI_HI
)) {
325 pb
= (struct adspcmd
*)gbuf_rptr(mp
);
326 gbuf_wset(mp
,sizeof(struct adspcmd
));
328 bzero((caddr_t
) pb
, sizeof(struct adspcmd
));
330 pb
->csCode
= dspRead
;
331 pb
->ioResult
= errAborted
;
332 completepb(sp
, pb
); /* send fake read completion */
336 RemoveCCB(sp
, 0); /* Will call completion routine */
338 sp
->userFlags
&= ~eClosed
;
345 * Also called for dspRemove and dspCLRemove.
346 * Must handle case of multiple close calls being issued (without
347 * abort bit set) Can only allow one pending remove though.
350 * --> ccbRefNum refnum of connection end
351 * --> abort abort the connection
357 * errRefNum Bad connection Refnum
359 int adspClose(sp
, pb
) /* (DSPPBPtr pb) */
361 register struct adspcmd
*pb
;
366 /* Must execute nearly all of this with ints off because user could
367 * be issuing a second dspRemove while the first is pending. Until
368 * we can detect this, we must not allow interrupts.
369 * Also, we can't handle the case where a close was issued earlier,
370 * and now this is the remove. If the write completion for the
371 * close advice packet occurs in the middle of this, we might
376 pb
->ioResult
= errRefNum
;
383 if (pb
->csCode
== (short)dspCLRemove
) { /* Remove connection listener */
384 if (sp
->state
!= (short)sListening
) { /* But it's not a listener! */
385 pb
->ioResult
= errState
;
388 CompleteQueue(&sp
->opb
, errAborted
); /* Complete all dspListens */
389 RemoveCCB(sp
, pb
); /* Will call completion routine */
395 * Either dspClose or dspRemove
398 if (sp
->removing
) { /* Don't allow dspRemove or dspClose */
399 /* after one dspRemove has been issued. */
400 pb
->ioResult
= errState
;
406 * The previous Macintosh ADSP allowed you to call close on a
407 * connection that was in the process of opening or passively
408 * waiting for an open request. It is also legal to close a
409 * connection that is already closed. No error will be generated.
411 * It is also legal to issue a second close call while the first
414 if (pb
->csCode
== (short)dspClose
) {
415 ATDISABLE(s
, sp
->lock
);
416 if ((sp
->state
== (short)sPassive
) || (sp
->state
== (short)sOpening
)) {
418 ATENABLE(s
, sp
->lock
);
419 DoClose(sp
, errAborted
, 0);
421 adspioc_ack(0, pb
->ioc
, pb
->gref
);
425 if (sp
->state
== (word
)sClosed
) { /* Ok to close a closed connection */
426 ATENABLE(s
, sp
->lock
);
428 adspioc_ack(0, pb
->ioc
, pb
->gref
);
431 if ((sp
->state
!= (word
)sOpen
) && (sp
->state
!= (word
)sClosing
)) {
432 ATENABLE(s
, sp
->lock
);
433 pb
->ioResult
= errState
;
437 sp
->state
= sClosing
; /* No matter what, we're closing */
438 ATENABLE(s
, sp
->lock
);
441 else { /* dspRemove */
442 ATDISABLE(s
, sp
->lock
);
443 sp
->removing
= 1; /* Prevent allowing another dspClose. */
444 /* Tells completion routine of close */
445 /* packet to remove us. */
447 if (sp
->state
== sPassive
|| sp
->state
== sClosed
||
448 sp
->state
== sOpening
) {
450 ATENABLE(s
, sp
->lock
);
451 DoClose(sp
, errAborted
, 0); /* Will remove CCB! */
453 } else { /* sClosing & sOpen */
454 sp
->state
= sClosing
;
455 ATENABLE(s
, sp
->lock
);
460 if (pb
->u
.closeParams
.abort
|| CheckOkToClose(sp
)) /* going to close */
462 AbortIO(sp
, errAborted
);
463 sp
->sendCtl
= B_CTL_CLOSE
; /* Send close advice */
467 if ( (mp
= gbuf_copym(pb
->mp
)) ) { /* duplicate user request */
468 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user */
469 pb
= (struct adspcmd
*)gbuf_rptr(mp
); /* get new parameter block */
472 ATDISABLE(s
, sp
->lock
);
473 qAddToEnd(&sp
->opb
, pb
); /* and save it */
474 ATENABLE(s
, sp
->lock
);
477 adspioc_ack(0, pb
->ioc
, pb
->gref
); /* release user, and keep no copy
478 * for kernel bookkeeping, yetch!
486 static void qRemove(qptr
, elem
)
487 register CCBPtr qptr
;
488 register CCBPtr elem
;
492 ATDISABLE(s
, adspall_lock
);
493 while(qptr
->ccbLink
) {
494 if ((DSPPBPtr
)(qptr
->ccbLink
) == (DSPPBPtr
)elem
) {
495 qptr
->ccbLink
= elem
->ccbLink
;
497 ATENABLE(s
, adspall_lock
);
500 qptr
= qptr
->ccbLink
;
502 ATENABLE(s
, adspall_lock
);
509 register struct adspcmd
*pb
;
512 ATDISABLE(l
, sp
->lockClose
);
513 ATDISABLE(s
, sp
->lock
);
514 if ((sp
->state
== sClosing
) || (sp
->state
== sClosed
)) {
515 ATENABLE(s
, sp
->lock
);
516 ATENABLE(l
, sp
->lockClose
);
520 ATENABLE(s
, sp
->lock
);
521 CheckReadQueue(sp
); /* try to deliver all remaining data */
523 if ( (mp
= gbuf_alloc(sizeof(struct adspcmd
), PRI_HI
)) ) {
524 pb
= (struct adspcmd
*)gbuf_rptr(mp
);
525 gbuf_wset(mp
,sizeof(struct adspcmd
));
529 pb
->csCode
= dspClose
;
531 completepb(sp
, pb
); /* send close completion */
534 if ((sp
->userFlags
& eClosed
) == 0)
535 DoClose(sp
, errAborted
, -1); /* abort send requests and timers */
537 ATENABLE(l
, sp
->lockClose
);