|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
24: * All Rights Reserved.
25: */
26:
27: /* dspClose.c
28: * From Mike Shoemaker v01.16 06/29/90 mbs
29: */
30: /*
31: * Change log:
32: * 06/29/95 - Modified to handle flow control for writing (Tuyen Nguyen)
33: * Modified for MP, 1996 by Tuyen Nguyen
34: * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
35: */
36:
37: #include <sys/errno.h>
38: #include <sys/types.h>
39: #include <sys/param.h>
40: #include <machine/spl.h>
41: #include <sys/systm.h>
42: #include <sys/kernel.h>
43: #include <sys/proc.h>
44: #include <sys/filedesc.h>
45: #include <sys/fcntl.h>
46: #include <sys/mbuf.h>
47: #include <sys/socket.h>
48: #include <sys/socketvar.h>
49: #include <sys/time.h>
50:
51: #include <netat/sysglue.h>
52: #include <netat/appletalk.h>
53: #include <netat/ddp.h>
54: #include <netat/at_pcb.h>
55: #include <netat/debug.h>
56: #include <netat/adsp.h>
57: #include <netat/adsp_internal.h>
58:
59: extern atlock_t adspall_lock;
60:
61: static void qRemove(CCBPtr, CCBPtr);
62:
63:
64: /*
65: * CheckOkToClose
66: *
67: * Check to see if it is OK to close this connection cleanly.
68: *
69: * INPUTS:
70: * Stream pointer
71: * OUTPUTS:
72: * True if no outstanding transactions and we can close cleanly
73: */
74: int CheckOkToClose(sp) /* (CCBPtr sp) */
75: CCBPtr sp;
76: {
77:
78: if (sp->sData) /* Outstanding data ? */
79: return 0;
80:
81: if (sp->sapb) /* Outstanding send attention ? */
82: return 0;
83:
84: if (sp->frpb) /* Outstanding forward reset ? */
85: return 0;
86:
87: if (sp->sendAttnAck)
88: return 0;
89:
90: if (sp->sendDataAck)
91: return 0;
92:
93: /*
94: * Must be OK to close
95: */
96: sp->sendCtl |= B_CTL_CLOSE; /* So, need to send close advice */
97: sp->callSend = 1;
98:
99: return 1; /* It's OK to close */
100: }
101:
102:
103: /*
104: * CompleteQueue
105: *
106: * Given the address of the head of a queue of DSP parameter blocks, zero
107: * the queue, and complete each item on the queue with the given result
108: * code.
109: *
110: * INPUTS:
111: * qhead Address of ptr to first queue element
112: * code The result code
113: * OUTPUTS:
114: * none
115: */
116: int CompleteQueue(qhead, code) /* (DSPPBPtr FPTR qhead, OSErr code) */
117: struct adspcmd **qhead;
118: int code;
119: {
120: register struct adspcmd *p;
121: register struct adspcmd *n;
122: register gref_t *gref;
123: register int total = 0;
124: CCBPtr sp = 0;
125: int s;
126:
127: n = *qhead; /* Get first item */
128: *qhead = 0; /* Zero out the queue */
129: if (n) {
130: gref = n->gref;
131: if (gref->info) {
132: sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
133: atalk_flush(sp->gref);
134: ATDISABLE(s, sp->lock);
135: }
136: }
137:
138: while (p = n) { /* while items left */
139: n = (struct adspcmd *)(p->qLink); /* Save next guy */
140: p->ioResult = code;
141: if (sp) {
142: completepb(sp, p); /* complete the copy of the request */
143: total++;
144: } else
145: gbuf_freem(p->mp);
146: } /* while */
147: if (sp)
148: ATENABLE(s, sp->lock);
149: return(total);
150: }
151:
152: /*
153: * RemoveCCB
154: *
155: * Called from do close to free up the user's CCB. So, we remove the
156: * CCB from the list of CCB's.
157: *
158: * INPUTS:
159: * sp pointer to ccb
160: * pb a remove param block to complete when done
161: * OUTPUTS:
162: * none
163: */
164:
165: void RemoveCCB(sp, pb) /* (CCBPtr sp, DSPPBPtr pb) */
166: CCBPtr sp;
167: struct adspcmd *pb;
168: {
169: gref_t *gref;
170:
171: if (sp->gref == 0)
172: return;
173: /*
174: * Unlink CCB from list
175: */
176: qRemove(AT_ADSP_STREAMS, sp); /* remove sp from active streams queue */
177:
178: if (pb) {
179: pb->ioResult = 0;
180: if (pb->ioc) /* is this a current or queued request */
181: adspioc_ack(0, pb->ioc, pb->gref); /* current */
182: else {
183: completepb(sp, pb); /* queued */
184: }
185:
186: if (sp->opb && (pb != sp->opb)) { /* if the pb requested is not the */
187: pb = sp->opb; /* waiting open pb, complete it too */
188: sp->opb = 0;
189: pb->ioResult = 0;
190: completepb(sp, pb);
191: } else {
192: sp->opb = 0;
193: }
194: }
195: gref = sp->gref;
196: sp->gref = 0;
197: if (gref->info == (char *)sp->sp_mp) { /* queue head is still valid */
198: unsigned char skt;
199:
200: if ((skt = sp->localSocket) != 0) {
201: if (adspDeassignSocket(sp) == 0)
202: ddp_notify_nbp(skt, sp->pid, DDP_ADSP);
203: }
204:
205: if (gref->info) {
206: gbuf_freem((gbuf_t *)gref->info); /* free the CCB */
207: gref->info = 0;
208: }
209: } else
210: gbuf_freem(sp->sp_mp); /* our head is already gone, be sure
211: * to release our resources too */
212: }
213:
214: int AbortIO(sp, err)
215: CCBPtr sp;
216: short err;
217: {
218: register int total;
219:
220: if (sp->gref == 0)
221: return 0;
222: /*
223: * Complete all outstanding transactions.
224: */
225: total += CompleteQueue(&sp->sapb, err); /* Abort outstanding send attentions */
226: CompleteQueue(&sp->frpb, err); /* Abort outstanding forward resets */
227:
228: if (sp->sbuf_mb) { /* clear the send queue */
229: gbuf_freel(sp->sbuf_mb);
230: sp->sbuf_mb = 0;
231: }
232:
233: if (sp->csbuf_mb) {
234: gbuf_freem(sp->csbuf_mb);
235: sp->csbuf_mb = 0;
236: }
237: sp->sData = 0;
238:
239: return(total);
240: }
241:
242: /*
243: * DoClose
244: *
245: * Called from several places (probe timeout, recv close advice,
246: * dspRemove, etc.) to change state of connection to closed and
247: * complete all outstanding I/O.
248: *
249: * Will also remove the CCB if there is a dsp remove pending.
250: *
251: * INPUTS:
252: * sp An ADSP stream
253: * OUTPUTS:
254: * none
255: */
256: void DoClose(sp, err, force_abort) /* (CCBPtr sp, OSErr err) */
257: register CCBPtr sp;
258: int err;
259: {
260: register struct adspcmd *pb, *np;
261: register gbuf_t *mp;
262: int aborted_count;
263:
264: dPrintf(D_M_ADSP, D_L_TRACE, ("DoClose: pid=%d,e=%d,a=%d,s=%d,r=%d\n",
265: sp->pid, err, force_abort, sp->localSocket, sp->removing));
266: sp->userFlags |= eClosed; /* Set flag */
267: sp->state = sClosed;
268: sp->openState = O_STATE_NOTHING;
269:
270: /*
271: * Clean up any timer elements
272: */
273: RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
274: RemoveTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer);
275: RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
276: RemoveTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer);
277: RemoveTimerElem(&adspGlobal.fastTimers, &sp->ResetTimer);
278:
279: aborted_count = AbortIO(sp, err);
280: np = sp->opb; /* Get list of close/removes to complete */
281: sp->opb = 0; /* set this list null */
282:
283: while (pb = np) { /* Handle all of the close/remove param blks */
284: np = (struct adspcmd *)pb->qLink; /* Get next guy (if any) */
285: pb->qLink = 0;
286: pb->ioResult = err;
287: completepb(sp, pb);
288: }
289: if (sp->removing && (force_abort >= 0)) { /* Abort outstanding receives */
290: aborted_count += CompleteQueue(&sp->rpb, err);
291:
292: if (sp->deferred_mb) {
293: gbuf_freel(sp->deferred_mb);
294: sp->deferred_mb = 0;
295: }
296: if (sp->attn_mb) {
297: gbuf_freem(sp->attn_mb);
298: sp->attn_mb = 0;
299: }
300: if (sp->rbuf_mb) { /* clear the rcv queue */
301: gbuf_freem(sp->rbuf_mb);
302: sp->rbuf_mb = 0;
303: }
304: if (sp->crbuf_mb) {
305: gbuf_freem(sp->crbuf_mb);
306: sp->crbuf_mb = 0;
307: }
308: sp->rData = 0;
309:
310: /* if our connection has been timed out */
311: /* and the user wasn't notified of the TearDown */
312: /* because of pending requests on this socket */
313: /* then fake a read completion to force the notification */
314:
315: if (force_abort && aborted_count == 0) {
316: if (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) {
317: pb = (struct adspcmd *)gbuf_rptr(mp);
318: gbuf_wset(mp,sizeof(struct adspcmd));
319:
320: bzero((caddr_t) pb, sizeof(struct adspcmd));
321: pb->mp = mp;
322: pb->csCode = dspRead;
323: pb->ioResult = errAborted;
324: completepb(sp, pb); /* send fake read completion */
325: }
326: }
327: sp->removing = 0;
328: RemoveCCB(sp, 0); /* Will call completion routine */
329: }
330: sp->userFlags &= ~eClosed;
331: }
332:
333:
334: /*
335: * dspClose
336: *
337: * Also called for dspRemove and dspCLRemove.
338: * Must handle case of multiple close calls being issued (without
339: * abort bit set) Can only allow one pending remove though.
340: *
341: * INPUTS:
342: * --> ccbRefNum refnum of connection end
343: * --> abort abort the connection
344: *
345: * OUTPUTS:
346: * none
347: *
348: * ERRORS:
349: * errRefNum Bad connection Refnum
350: */
351: int adspClose(sp, pb) /* (DSPPBPtr pb) */
352: register CCBPtr sp;
353: register struct adspcmd *pb;
354: {
355: int s;
356: register gbuf_t *mp;
357:
358: /* Must execute nearly all of this with ints off because user could
359: * be issuing a second dspRemove while the first is pending. Until
360: * we can detect this, we must not allow interrupts.
361: * Also, we can't handle the case where a close was issued earlier,
362: * and now this is the remove. If the write completion for the
363: * close advice packet occurs in the middle of this, we might
364: * foul up.
365: */
366:
367: if (sp == 0) {
368: pb->ioResult = errRefNum;
369: return EINVAL;
370: }
371:
372: /*
373: * Handle dspCLRemove
374: */
375: if (pb->csCode == (short)dspCLRemove) { /* Remove connection listener */
376: if (sp->state != (short)sListening) { /* But it's not a listener! */
377: pb->ioResult = errState;
378: return EINVAL;
379: }
380: CompleteQueue(&sp->opb, errAborted); /* Complete all dspListens */
381: RemoveCCB(sp, pb); /* Will call completion routine */
382: return 0;
383: }
384:
385:
386: /*
387: * Either dspClose or dspRemove
388: */
389:
390: if (sp->removing) { /* Don't allow dspRemove or dspClose */
391: /* after one dspRemove has been issued. */
392: pb->ioResult = errState;
393: return EINVAL;
394: }
395:
396:
397: /*
398: * The previous Macintosh ADSP allowed you to call close on a
399: * connection that was in the process of opening or passively
400: * waiting for an open request. It is also legal to close a
401: * connection that is already closed. No error will be generated.
402: *
403: * It is also legal to issue a second close call while the first
404: * is still pending.
405: */
406: if (pb->csCode == (short)dspClose) {
407: ATDISABLE(s, sp->lock);
408: if ((sp->state == (short)sPassive) || (sp->state == (short)sOpening)) {
409: sp->state = sClosed;
410: ATENABLE(s, sp->lock);
411: DoClose(sp, errAborted, 0);
412: pb->ioResult = 0;
413: adspioc_ack(0, pb->ioc, pb->gref);
414: return 0;
415: }
416:
417: if (sp->state == (word)sClosed) { /* Ok to close a closed connection */
418: ATENABLE(s, sp->lock);
419: pb->ioResult = 0;
420: adspioc_ack(0, pb->ioc, pb->gref);
421: return 0;
422: }
423: if ((sp->state != (word)sOpen) && (sp->state != (word)sClosing)) {
424: ATENABLE(s, sp->lock);
425: pb->ioResult = errState;
426: return EINVAL;
427: }
428:
429: sp->state = sClosing; /* No matter what, we're closing */
430: ATENABLE(s, sp->lock);
431: } /* dspClose */
432:
433: else { /* dspRemove */
434: ATDISABLE(s, sp->lock);
435: sp->removing = 1; /* Prevent allowing another dspClose. */
436: /* Tells completion routine of close */
437: /* packet to remove us. */
438:
439: if (sp->state == sPassive || sp->state == sClosed ||
440: sp->state == sOpening) {
441: sp->state = sClosed;
442: ATENABLE(s, sp->lock);
443: DoClose(sp, errAborted, 0); /* Will remove CCB! */
444: return 0;
445: } else { /* sClosing & sOpen */
446: sp->state = sClosing;
447: ATENABLE(s, sp->lock);
448: }
449:
450: } /* dspRemove */
451:
452: if (pb->u.closeParams.abort || CheckOkToClose(sp)) /* going to close */
453: {
454: AbortIO(sp, errAborted);
455: sp->sendCtl = B_CTL_CLOSE; /* Send close advice */
456: }
457:
458: pb->ioResult = 1;
459: if ( (mp = gbuf_copym(pb->mp)) ) { /* duplicate user request */
460: adspioc_ack(0, pb->ioc, pb->gref); /* release user */
461: pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */
462: pb->ioc = 0;
463: pb->mp = mp;
464: ATDISABLE(s, sp->lock);
465: qAddToEnd(&sp->opb, pb); /* and save it */
466: ATENABLE(s, sp->lock);
467: } else {
468: pb->ioResult = 0;
469: adspioc_ack(0, pb->ioc, pb->gref); /* release user, and keep no copy
470: * for kernel bookkeeping, yetch!
471: */
472: }
473: CheckSend(sp);
474:
475: return 0;
476: }
477:
478: static void qRemove(qptr, elem)
479: register CCBPtr qptr;
480: register CCBPtr elem;
481: {
482: int s;
483:
484: ATDISABLE(s, adspall_lock);
485: while(qptr->ccbLink) {
486: if ((DSPPBPtr)(qptr->ccbLink) == (DSPPBPtr)elem) {
487: qptr->ccbLink = elem->ccbLink;
488: elem->ccbLink = 0;
489: ATENABLE(s, adspall_lock);
490: return;
491: }
492: qptr = qptr->ccbLink;
493: }
494: ATENABLE(s, adspall_lock);
495: }
496:
497: int RxClose(sp)
498: register CCBPtr sp;
499: {
500: register gbuf_t *mp;
501: register struct adspcmd *pb;
502: int s, l;
503:
504: ATDISABLE(l, sp->lockClose);
505: ATDISABLE(s, sp->lock);
506: if ((sp->state == sClosing) || (sp->state == sClosed)) {
507: ATENABLE(s, sp->lock);
508: ATENABLE(l, sp->lockClose);
509: return 0;
510: }
511: sp->state = sClosed;
512: ATENABLE(s, sp->lock);
513: CheckReadQueue(sp); /* try to deliver all remaining data */
514:
515: if ( (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) ) {
516: pb = (struct adspcmd *)gbuf_rptr(mp);
517: gbuf_wset(mp,sizeof(struct adspcmd));
518: pb->ioc = 0;
519: pb->mp = mp;
520:
521: pb->csCode = dspClose;
522: pb->ioResult = 0;
523: completepb(sp, pb); /* send close completion */
524: }
525:
526: if ((sp->userFlags & eClosed) == 0)
527: DoClose(sp, errAborted, -1); /* abort send requests and timers */
528:
529: ATENABLE(l, sp->lockClose);
530: return 0;
531: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.