1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * RxAttn.c
30 *
31 * From v01.12  06/12/90 mbs
32 *   Modified, April 9, 1997 by Tuyen Nguyen for MacOSX.
33 */
34
35#include <sys/errno.h>
36#include <sys/types.h>
37#include <sys/param.h>
38#include <machine/spl.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/proc.h>
42#include <sys/filedesc.h>
43#include <sys/fcntl.h>
44#include <sys/mbuf.h>
45#include <sys/socket.h>
46#include <sys/time.h>
47
48#include <netat/sysglue.h>
49#include <netat/appletalk.h>
50#include <netat/at_pcb.h>
51#include <netat/debug.h>
52#include <netat/adsp.h>
53#include <netat/adsp_internal.h>
54
55/*
56 * Used to search down queue of sessions for a session that matches
57 * sender and source connection ID
58*/
59typedef struct
60{
61	AddrUnion   addr;
62	word        srcCID;
63} MATCH_SENDER, *MATCH_SENDERPtr;
64
65/*
66 * MatchSender
67 *
68 */
69static boolean MatchSender(CCBPtr, MATCH_SENDERPtr);
70
71static boolean MatchSender(sp, m) /* (CCBPtr sp, MATCH_SENDERPtr m) */
72    CCBPtr sp;
73    MATCH_SENDERPtr m;
74{
75
76    if (sp->state != sOpen && sp->state != sClosing)
77	return 0;
78
79    if (sp->remCID != m->srcCID)
80	return 0;
81
82    if (sp->remoteAddress.a.node != m->addr.a.node)
83	return 0;
84    if (sp->remoteAddress.a.socket != m->addr.a.socket)
85	return 0;
86    if (sp->remoteAddress.a.net && m->addr.a.net &&
87	(sp->remoteAddress.a.net != m->addr.a.net))
88	return 0;
89
90    return 1;
91}
92
93
94/*
95 * FindSender
96 *
97 * Given an ADSP Packet, find the stream it is associated with.
98 *
99 * This should only be used for ADSP Packets that could be received
100 * by an OPEN connection.
101 *
102 * INPUTS:
103 *    Pointer to ADSP header & address of sender
104 * OUTPUTS:
105 *    Pointer to stream if found, else 0
106 */
107CCBPtr FindSender(f, a)		/* (ADSP_FRAMEPtr f, AddrUnion a) */
108    ADSP_FRAMEPtr f;
109    AddrUnion a;
110{
111    MATCH_SENDER m;
112
113    m.addr = a;
114    m.srcCID = UAS_VALUE_NTOH(f->CID);
115    return (CCBPtr)qfind_m((CCB *)AT_ADSP_STREAMS, &m, (ProcPtr)MatchSender);
116}
117
118/*
119 * RXAttention
120 *
121 * We just got an Attention Packet.
122 * See if it came from anybody we know.
123 * Then check to see if it is an attention data packet or acknowledgement
124 *
125 * Interrupts are masked OFF at this point.
126 *
127 * INPUTS:
128 *    stream pointer
129 *    Pointer to ADSP header,
130 *    Length of header plus data
131 * OUTPUTS:
132 *    Returns 1 if packet was ignored
133 */
134int RXAttention(sp, mp, f, len)	/* (CCBPtr sp, ADSP_FRAMEPtr f, word len) */
135    CCBPtr sp;
136    gbuf_t *mp;
137    ADSP_FRAMEPtr f;
138    int len;
139{
140    int offset;
141    struct adspcmd *pb;
142    long diff;
143
144    if (UAS_VALUE(f->pktRecvWdw))		/* This field must be 0 in attn pkts */
145	return 1;
146
147    if ((f->descriptor ==
148	 (char)(ADSP_ATTENTION_BIT | ADSP_ACK_REQ_BIT)) && /* Attention Data */
149	((sp->userFlags & eAttention) == 0)) /* & they read the previous */
150    {
151	diff = UAL_VALUE_NTOH(f->pktFirstByteSeq) - sp->attnRecvSeq;
152	if (diff > 0)		/* Hey, he missed one */
153	    return 1;
154
155	if (diff == 0)		/* This is the one we expected */
156	{
157	    len	-= ADSP_FRAME_LEN; /* remove adsp header */
158	    if (len < 2)	/* Poorly formed attn packet */
159		return 1;
160	    sp->attnCode = (f->data[0] << 8) + f->data[1]; /* Save attn code */
161	    sp->attn_mb = mp;
162	    offset = ((unsigned char *)&f->data[2]) - (unsigned char *)gbuf_rptr(mp);
163	    gbuf_rinc(mp,offset);
164	    sp->attnPtr = (unsigned char *)gbuf_rptr(mp);
165	    mp = 0;		/* mp has been queued don't free it */
166
167	    /* Interrupts are off here, or otherwise we have to do
168	     * these three operations automically.
169	     */
170	    sp->attnSize = len - 2; /* Tell user how many bytes */
171	    ++sp->attnRecvSeq;
172	    /* Set flag saying we got attn message */
173	    sp->userFlags |= eAttention;
174	    UrgentUser(sp);	/* Notify user */
175				/* BEFORE sending acknowledge */
176	}			/* in sequence */
177
178	sp->sendAttnAck = 1;	/* send attention ack for dupl. &
179				 * expected data */
180	sp->callSend = 1;
181    }				/* Attn Data */
182
183    /*
184     * Interrupts are OFF here, otherwise we have to do this atomically
185     */
186    /* Check to see if this acknowledges anything */
187    if ((sp->attnSendSeq + 1) == UAL_VALUE_NTOH(f->pktNextRecvSeq)) {
188	sp->attnSendSeq++;
189	if ((pb = sp->sapb) == 0) { /* We never sent data ? !!! */
190	    if (mp)
191		gbuf_freem(mp);
192	    return 0;
193	}
194
195	sp->sapb = (struct adspcmd *)pb->qLink;	/* Unlink from queue */
196
197	/* Remove timer */
198	RemoveTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer);
199
200	pb->ioResult = 0;
201	if (gbuf_cont(pb->mp)) {
202	    gbuf_freem(gbuf_cont(pb->mp)); /* free the data */
203	    gbuf_cont(pb->mp) = 0;
204	}
205	completepb(sp, pb);	/* Done with the send attention */
206
207	if (sp->sapb) {		/* Another send attention pending? */
208	    sp->sendAttnData = 1;
209	    sp->callSend = 1;
210	} else {
211	    if (sp->state == sClosing) /* this ack may allow us to close... */
212		CheckOkToClose(sp);
213	}
214    }
215    if (mp)
216	gbuf_freem(mp);
217    return 0;
218}
219