]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/adsp_Close.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / bsd / netat / adsp_Close.c
CommitLineData
1c79356b 1/*
8ad349bb 2 * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
1c79356b 3 *
8ad349bb 4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
1c79356b 5 *
8ad349bb
A
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
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
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.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
1c79356b
A
29 */
30/*
31 * Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
32 * All Rights Reserved.
33 */
34
35/* dspClose.c
36 * From Mike Shoemaker v01.16 06/29/90 mbs
37 */
38/*
39 * Change log:
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.
43 */
44
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>
51#include <sys/proc.h>
52#include <sys/filedesc.h>
53#include <sys/fcntl.h>
54#include <sys/mbuf.h>
55#include <sys/socket.h>
56#include <sys/socketvar.h>
57#include <sys/time.h>
58
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>
66
8ad349bb 67extern atlock_t adspall_lock;
1c79356b
A
68
69static void qRemove(CCBPtr, CCBPtr);
70
71
72/*
73 * CheckOkToClose
74 *
75 * Check to see if it is OK to close this connection cleanly.
76 *
77 * INPUTS:
78 * Stream pointer
79 * OUTPUTS:
80 * True if no outstanding transactions and we can close cleanly
81 */
82int CheckOkToClose(sp) /* (CCBPtr sp) */
83 CCBPtr sp;
84{
85
86 if (sp->sData) /* Outstanding data ? */
87 return 0;
88
89 if (sp->sapb) /* Outstanding send attention ? */
90 return 0;
91
92 if (sp->frpb) /* Outstanding forward reset ? */
93 return 0;
94
95 if (sp->sendAttnAck)
96 return 0;
97
98 if (sp->sendDataAck)
99 return 0;
100
101 /*
102 * Must be OK to close
103 */
104 sp->sendCtl |= B_CTL_CLOSE; /* So, need to send close advice */
105 sp->callSend = 1;
106
107 return 1; /* It's OK to close */
108}
109
110
111/*
112 * CompleteQueue
113 *
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
116 * code.
117 *
118 * INPUTS:
119 * qhead Address of ptr to first queue element
120 * code The result code
121 * OUTPUTS:
122 * none
123 */
124int CompleteQueue(qhead, code) /* (DSPPBPtr FPTR qhead, OSErr code) */
125 struct adspcmd **qhead;
126 int code;
127{
128 register struct adspcmd *p;
129 register struct adspcmd *n;
130 register gref_t *gref;
131 register int total = 0;
132 CCBPtr sp = 0;
8ad349bb 133 int s;
1c79356b
A
134
135 n = *qhead; /* Get first item */
136 *qhead = 0; /* Zero out the queue */
137 if (n) {
138 gref = n->gref;
139 if (gref->info) {
140 sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
141 atalk_flush(sp->gref);
8ad349bb 142 ATDISABLE(s, sp->lock);
1c79356b
A
143 }
144 }
145
146 while (p = n) { /* while items left */
147 n = (struct adspcmd *)(p->qLink); /* Save next guy */
148 p->ioResult = code;
149 if (sp) {
150 completepb(sp, p); /* complete the copy of the request */
151 total++;
152 } else
153 gbuf_freem(p->mp);
154 } /* while */
8ad349bb
A
155 if (sp)
156 ATENABLE(s, sp->lock);
1c79356b
A
157 return(total);
158}
159
160/*
161 * RemoveCCB
162 *
163 * Called from do close to free up the user's CCB. So, we remove the
164 * CCB from the list of CCB's.
165 *
166 * INPUTS:
167 * sp pointer to ccb
168 * pb a remove param block to complete when done
169 * OUTPUTS:
170 * none
171 */
172
173void RemoveCCB(sp, pb) /* (CCBPtr sp, DSPPBPtr pb) */
174 CCBPtr sp;
175 struct adspcmd *pb;
176{
177 gref_t *gref;
178
179 if (sp->gref == 0)
180 return;
181 /*
182 * Unlink CCB from list
183 */
55e303ae 184 qRemove((CCB *)AT_ADSP_STREAMS, sp); /* remove sp from active streams queue */
1c79356b
A
185
186 if (pb) {
187 pb->ioResult = 0;
188 if (pb->ioc) /* is this a current or queued request */
189 adspioc_ack(0, pb->ioc, pb->gref); /* current */
190 else {
191 completepb(sp, pb); /* queued */
192 }
193
194 if (sp->opb && (pb != sp->opb)) { /* if the pb requested is not the */
195 pb = sp->opb; /* waiting open pb, complete it too */
196 sp->opb = 0;
197 pb->ioResult = 0;
198 completepb(sp, pb);
199 } else {
200 sp->opb = 0;
201 }
202 }
203 gref = sp->gref;
204 sp->gref = 0;
205 if (gref->info == (char *)sp->sp_mp) { /* queue head is still valid */
206 unsigned char skt;
207
208 if ((skt = sp->localSocket) != 0) {
209 if (adspDeassignSocket(sp) == 0)
210 ddp_notify_nbp(skt, sp->pid, DDP_ADSP);
211 }
212
213 if (gref->info) {
214 gbuf_freem((gbuf_t *)gref->info); /* free the CCB */
215 gref->info = 0;
216 }
217 } else
218 gbuf_freem(sp->sp_mp); /* our head is already gone, be sure
219 * to release our resources too */
220}
221
222int AbortIO(sp, err)
223 CCBPtr sp;
224 short err;
225{
226 register int total;
227
228 if (sp->gref == 0)
229 return 0;
230 /*
231 * Complete all outstanding transactions.
232 */
91447636 233 total = CompleteQueue(&sp->sapb, err); /* Abort outstanding send attentions */
1c79356b
A
234 CompleteQueue(&sp->frpb, err); /* Abort outstanding forward resets */
235
236 if (sp->sbuf_mb) { /* clear the send queue */
237 gbuf_freel(sp->sbuf_mb);
238 sp->sbuf_mb = 0;
239 }
240
241 if (sp->csbuf_mb) {
242 gbuf_freem(sp->csbuf_mb);
243 sp->csbuf_mb = 0;
244 }
245 sp->sData = 0;
246
247 return(total);
248}
249
250/*
251 * DoClose
252 *
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.
256 *
257 * Will also remove the CCB if there is a dsp remove pending.
258 *
259 * INPUTS:
260 * sp An ADSP stream
261 * OUTPUTS:
262 * none
263 */
264void DoClose(sp, err, force_abort) /* (CCBPtr sp, OSErr err) */
265 register CCBPtr sp;
266 int err;
267{
268 register struct adspcmd *pb, *np;
269 register gbuf_t *mp;
270 int aborted_count;
271
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 */
275 sp->state = sClosed;
276 sp->openState = O_STATE_NOTHING;
277
278 /*
279 * Clean up any timer elements
280 */
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);
286
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 */
290
291 while (pb = np) { /* Handle all of the close/remove param blks */
292 np = (struct adspcmd *)pb->qLink; /* Get next guy (if any) */
293 pb->qLink = 0;
294 pb->ioResult = err;
295 completepb(sp, pb);
296 }
297 if (sp->removing && (force_abort >= 0)) { /* Abort outstanding receives */
298 aborted_count += CompleteQueue(&sp->rpb, err);
299
300 if (sp->deferred_mb) {
301 gbuf_freel(sp->deferred_mb);
302 sp->deferred_mb = 0;
303 }
304 if (sp->attn_mb) {
305 gbuf_freem(sp->attn_mb);
306 sp->attn_mb = 0;
307 }
308 if (sp->rbuf_mb) { /* clear the rcv queue */
309 gbuf_freem(sp->rbuf_mb);
310 sp->rbuf_mb = 0;
311 }
312 if (sp->crbuf_mb) {
313 gbuf_freem(sp->crbuf_mb);
314 sp->crbuf_mb = 0;
315 }
316 sp->rData = 0;
317
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 */
322
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));
327
328 bzero((caddr_t) pb, sizeof(struct adspcmd));
329 pb->mp = mp;
330 pb->csCode = dspRead;
331 pb->ioResult = errAborted;
332 completepb(sp, pb); /* send fake read completion */
333 }
334 }
335 sp->removing = 0;
336 RemoveCCB(sp, 0); /* Will call completion routine */
337 }
338 sp->userFlags &= ~eClosed;
339}
340
341
342/*
343 * dspClose
344 *
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.
348 *
349 * INPUTS:
350 * --> ccbRefNum refnum of connection end
351 * --> abort abort the connection
352 *
353 * OUTPUTS:
354 * none
355 *
356 * ERRORS:
357 * errRefNum Bad connection Refnum
358 */
359int adspClose(sp, pb) /* (DSPPBPtr pb) */
360 register CCBPtr sp;
361 register struct adspcmd *pb;
362{
8ad349bb 363 int s;
1c79356b
A
364 register gbuf_t *mp;
365
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
372 * foul up.
373 */
374
375 if (sp == 0) {
376 pb->ioResult = errRefNum;
377 return EINVAL;
378 }
379
380 /*
381 * Handle dspCLRemove
382 */
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;
386 return EINVAL;
387 }
388 CompleteQueue(&sp->opb, errAborted); /* Complete all dspListens */
389 RemoveCCB(sp, pb); /* Will call completion routine */
390 return 0;
391 }
392
393
394 /*
395 * Either dspClose or dspRemove
396 */
397
398 if (sp->removing) { /* Don't allow dspRemove or dspClose */
399 /* after one dspRemove has been issued. */
400 pb->ioResult = errState;
401 return EINVAL;
402 }
403
404
405 /*
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.
410 *
411 * It is also legal to issue a second close call while the first
412 * is still pending.
413 */
414 if (pb->csCode == (short)dspClose) {
8ad349bb 415 ATDISABLE(s, sp->lock);
1c79356b
A
416 if ((sp->state == (short)sPassive) || (sp->state == (short)sOpening)) {
417 sp->state = sClosed;
8ad349bb 418 ATENABLE(s, sp->lock);
1c79356b
A
419 DoClose(sp, errAborted, 0);
420 pb->ioResult = 0;
421 adspioc_ack(0, pb->ioc, pb->gref);
422 return 0;
423 }
424
425 if (sp->state == (word)sClosed) { /* Ok to close a closed connection */
8ad349bb 426 ATENABLE(s, sp->lock);
1c79356b
A
427 pb->ioResult = 0;
428 adspioc_ack(0, pb->ioc, pb->gref);
429 return 0;
430 }
431 if ((sp->state != (word)sOpen) && (sp->state != (word)sClosing)) {
8ad349bb 432 ATENABLE(s, sp->lock);
1c79356b
A
433 pb->ioResult = errState;
434 return EINVAL;
435 }
436
437 sp->state = sClosing; /* No matter what, we're closing */
8ad349bb 438 ATENABLE(s, sp->lock);
1c79356b
A
439 } /* dspClose */
440
441 else { /* dspRemove */
8ad349bb 442 ATDISABLE(s, sp->lock);
1c79356b
A
443 sp->removing = 1; /* Prevent allowing another dspClose. */
444 /* Tells completion routine of close */
445 /* packet to remove us. */
446
447 if (sp->state == sPassive || sp->state == sClosed ||
448 sp->state == sOpening) {
449 sp->state = sClosed;
8ad349bb 450 ATENABLE(s, sp->lock);
1c79356b
A
451 DoClose(sp, errAborted, 0); /* Will remove CCB! */
452 return 0;
8ad349bb 453 } else { /* sClosing & sOpen */
1c79356b 454 sp->state = sClosing;
8ad349bb
A
455 ATENABLE(s, sp->lock);
456 }
1c79356b
A
457
458 } /* dspRemove */
459
460 if (pb->u.closeParams.abort || CheckOkToClose(sp)) /* going to close */
461 {
462 AbortIO(sp, errAborted);
463 sp->sendCtl = B_CTL_CLOSE; /* Send close advice */
464 }
465
466 pb->ioResult = 1;
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 */
470 pb->ioc = 0;
471 pb->mp = mp;
8ad349bb 472 ATDISABLE(s, sp->lock);
1c79356b 473 qAddToEnd(&sp->opb, pb); /* and save it */
8ad349bb 474 ATENABLE(s, sp->lock);
1c79356b
A
475 } else {
476 pb->ioResult = 0;
477 adspioc_ack(0, pb->ioc, pb->gref); /* release user, and keep no copy
478 * for kernel bookkeeping, yetch!
479 */
480 }
481 CheckSend(sp);
482
483 return 0;
484}
485
486static void qRemove(qptr, elem)
487 register CCBPtr qptr;
488 register CCBPtr elem;
489{
8ad349bb 490 int s;
1c79356b 491
8ad349bb 492 ATDISABLE(s, adspall_lock);
1c79356b
A
493 while(qptr->ccbLink) {
494 if ((DSPPBPtr)(qptr->ccbLink) == (DSPPBPtr)elem) {
495 qptr->ccbLink = elem->ccbLink;
496 elem->ccbLink = 0;
8ad349bb 497 ATENABLE(s, adspall_lock);
1c79356b
A
498 return;
499 }
500 qptr = qptr->ccbLink;
501 }
8ad349bb 502 ATENABLE(s, adspall_lock);
1c79356b
A
503}
504
505int RxClose(sp)
506 register CCBPtr sp;
507{
508 register gbuf_t *mp;
509 register struct adspcmd *pb;
8ad349bb 510 int s, l;
1c79356b 511
8ad349bb
A
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);
1c79356b 517 return 0;
8ad349bb 518 }
1c79356b 519 sp->state = sClosed;
8ad349bb 520 ATENABLE(s, sp->lock);
1c79356b
A
521 CheckReadQueue(sp); /* try to deliver all remaining data */
522
523 if ( (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) ) {
524 pb = (struct adspcmd *)gbuf_rptr(mp);
525 gbuf_wset(mp,sizeof(struct adspcmd));
526 pb->ioc = 0;
527 pb->mp = mp;
528
529 pb->csCode = dspClose;
530 pb->ioResult = 0;
531 completepb(sp, pb); /* send close completion */
532 }
533
534if ((sp->userFlags & eClosed) == 0)
535 DoClose(sp, errAborted, -1); /* abort send requests and timers */
536
8ad349bb 537 ATENABLE(l, sp->lockClose);
1c79356b
A
538 return 0;
539}