]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/atp_misc.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / netat / atp_misc.c
CommitLineData
1c79356b
A
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) 1996-1998 Apple Computer, Inc.
24 * All Rights Reserved.
25 */
26
27/* Modified for MP, 1996 by Tuyen Nguyen
28 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
29 */
30#include <sys/errno.h>
31#include <sys/types.h>
32#include <sys/param.h>
33#include <machine/spl.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/proc.h>
37#include <sys/filedesc.h>
38#include <sys/fcntl.h>
39#include <sys/mbuf.h>
40#include <sys/ioctl.h>
41#include <sys/malloc.h>
42#include <sys/socket.h>
43
44#include <netat/sysglue.h>
45#include <netat/appletalk.h>
46#include <netat/ddp.h>
47#include <netat/at_pcb.h>
48#include <netat/atp.h>
49#include <netat/debug.h>
50
51extern atlock_t atpgen_lock;
52void atp_free();
53void atp_send(struct atp_trans *);
54
55/*
56 * The request timer retries a request, if all retries are used up
57 * it returns a NAK
58 */
59
60void
61atp_req_timeout(trp)
62register struct atp_trans *trp;
63{
64 int s;
65 register gbuf_t *m;
66 gref_t *gref;
67 struct atp_state *atp;
68 struct atp_trans *ctrp;
69
70 if ((atp = trp->tr_queue) == 0)
71 return;
72 ATDISABLE(s, atp->atp_lock);
73 if (atp->atp_flags & ATP_CLOSING) {
74 ATENABLE(s, atp->atp_lock);
75 return;
76 }
77 for (ctrp = atp->atp_trans_wait.head; ctrp; ctrp = ctrp->tr_list.next) {
78 if (ctrp == trp)
79 break;
80 }
81 if (ctrp != trp) {
82 ATENABLE(s, atp->atp_lock);
83 return;
84 }
85
86 if ((m = gbuf_cont(trp->tr_xmt)) == NULL)
87 m = trp->tr_xmt; /* issued via the new interface */
88
89 if (trp->tr_retry == 0) {
90 trp->tr_state = TRANS_FAILED;
91 if (m == trp->tr_xmt) {
92 trp->tr_xmt = NULL;
93l_notify:
94 gbuf_wset(m,1);
95 *gbuf_rptr(m) = 99;
96 gbuf_set_type(m, MSG_DATA);
97 gref = trp->tr_queue->atp_gref;
98 ATENABLE(s, atp->atp_lock);
99 atalk_putnext(gref, m);
100
101 return;
102 }
103 dPrintf(D_M_ATP_LOW,D_L_INFO, ("atp_req_timeout: skt=%d\n",
104 trp->tr_local_socket));
105 m = trp->tr_xmt;
106 switch(((ioc_t *)(gbuf_rptr(trp->tr_xmt)))->ioc_cmd) {
107 case AT_ATP_ISSUE_REQUEST:
108 trp->tr_xmt = NULL;
109 if (trp->tr_queue->dflag)
110 ((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_REQUEST_COMPLETE;
111 else if (trp->tr_bdsp == NULL) {
112 ATENABLE(s, atp->atp_lock);
113 gbuf_freem(m);
114 if (trp->tr_rsp_wait)
9bccf70c 115 wakeup(&trp->tr_event);
1c79356b
A
116 break;
117 }
118 ATENABLE(s, atp->atp_lock);
119 atp_iocnak(trp->tr_queue, m, ETIMEDOUT);
120 atp_free(trp);
121 return;
122
123 case AT_ATP_ISSUE_REQUEST_NOTE:
124 case AT_ATP_ISSUE_REQUEST_TICKLE:
125 trp->tr_xmt = gbuf_cont(m);
126 gbuf_cont(m) = NULL;
127 goto l_notify;
128 }
129 } else {
130 (AT_ATP_HDR(m))->bitmap = trp->tr_bitmap;
131
132 if (trp->tr_retry != (unsigned int) ATP_INFINITE_RETRIES)
133 trp->tr_retry--;
134 ATENABLE(s, atp->atp_lock);
135 atp_send(trp);
136 }
137}
138
139
140/*
141 * atp_free frees up a request, cleaning up the queues and freeing
142 * the request packet
143 * always called at 'lock'
144 */
145
146void atp_free(trp)
147register struct atp_trans *trp;
0b4e3aa0 148{
1c79356b
A
149 register struct atp_state *atp;
150 register int i;
151 int s;
152
153 dPrintf(D_M_ATP_LOW, D_L_TRACE,
154 ("atp_free: freeing trp 0x%x\n", (u_int) trp));
1c79356b 155
0b4e3aa0 156 ATDISABLE(s, atpgen_lock);
1c79356b 157
0b4e3aa0
A
158 if (trp->tr_state == TRANS_ABORTING) {
159 ATP_Q_REMOVE(atp_trans_abort, trp, tr_list);
160 trp->tr_state = TRANS_DONE;
1c79356b 161 }
0b4e3aa0
A
162 else {
163 if (trp->tr_tmo_func)
164 atp_untimout(atp_req_timeout, trp);
165
166 atp = trp->tr_queue;
167 ATP_Q_REMOVE(atp->atp_trans_wait, trp, tr_list);
168
169 if (trp->tr_xmt) {
170 gbuf_freem(trp->tr_xmt);
171 trp->tr_xmt = NULL;
172 }
173 for (i = 0; i < 8; i++) {
174 if (trp->tr_rcv[i]) {
175 gbuf_freem(trp->tr_rcv[i]);
176 trp->tr_rcv[i] = NULL;
177 }
178 }
179 if (trp->tr_bdsp) {
180 gbuf_freem(trp->tr_bdsp);
181 trp->tr_bdsp = NULL;
182 }
183
184 if (trp->tr_rsp_wait) {
185 trp->tr_state = TRANS_ABORTING;
186 ATP_Q_APPEND(atp_trans_abort, trp, tr_list);
9bccf70c 187 wakeup(&trp->tr_event);
0b4e3aa0
A
188 ATENABLE(s, atpgen_lock);
189 return;
1c79356b
A
190 }
191 }
0b4e3aa0 192
1c79356b
A
193 ATENABLE(s, atpgen_lock);
194 atp_trans_free(trp);
1c79356b
A
195} /* atp_free */
196
197
198/*
199 * atp_send transmits a request packet by queuing it (if it isn't already) and
200 * scheduling the queue
201 */
202
203void atp_send(trp)
204register struct atp_trans *trp;
205{
206 gbuf_t *m;
207 struct atp_state *atp;
208
209 dPrintf(D_M_ATP_LOW, D_L_OUTPUT, ("atp_send: trp=0x%x, loc=%d\n",
210 (u_int) trp->tr_queue, trp->tr_local_socket));
211
212 if ((atp = trp->tr_queue) != 0) {
213 if (trp->tr_state == TRANS_TIMEOUT) {
214 if ((m = gbuf_cont(trp->tr_xmt)) == NULL)
215 m = trp->tr_xmt;
216
217 /*
218 * Now either release the transaction or start the timer
219 */
220 if (!trp->tr_retry && !trp->tr_bitmap && !trp->tr_xo) {
221 m = (gbuf_t *)gbuf_copym(m);
222 atp_x_done(trp);
223 } else {
224 m = (gbuf_t *)gbuf_dupm(m);
225
226 atp_timout(atp_req_timeout, trp, trp->tr_timeout);
227 }
228
229 if (m) {
230 trace_mbufs(D_M_ATP_LOW, " m", m);
231 DDP_OUTPUT(m);
232 }
233 }
234 }
235}
236
237
238/*
239 * atp_reply sends all the available messages in the bitmap again
240 * by queueing us to the write service routine
241 */
242
243void atp_reply(rcbp)
244register struct atp_rcb *rcbp;
245{
246 register struct atp_state *atp;
247 register int i;
248 int s;
249
250 if ((atp = rcbp->rc_queue) != 0) {
251 ATDISABLE(s, atp->atp_lock);
252 for (i = 0; i < rcbp->rc_pktcnt; i++) {
253 if (rcbp->rc_bitmap&atp_mask[i])
254 rcbp->rc_snd[i] = 1;
255 else
256 rcbp->rc_snd[i] = 0;
257 }
258 if (rcbp->rc_rep_waiting == 0) {
259 rcbp->rc_state = RCB_SENDING;
260 rcbp->rc_rep_waiting = 1;
261 ATENABLE(s, atp->atp_lock);
262 atp_send_replies(atp, rcbp);
263 } else
264 ATENABLE(s, atp->atp_lock);
265 }
266}
267
268
269/*
270 * The rcb timer just frees the rcb, this happens when we missed a release for XO
271 */
272
273void atp_rcb_timer()
274{
275 int s;
276 register struct atp_rcb *rcbp;
277 register struct atp_rcb *next_rcbp;
278 extern struct atp_rcb_qhead atp_need_rel;
279 extern struct atp_trans *trp_tmo_rcb;
280
281l_again:
282 ATDISABLE(s, atpgen_lock);
283 for (rcbp = atp_need_rel.head; rcbp; rcbp = next_rcbp) {
284 next_rcbp = rcbp->rc_tlist.next;
285
286 if (abs(time.tv_sec - rcbp->rc_timestamp) > 30) {
287 ATENABLE(s, atpgen_lock);
288 atp_rcb_free(rcbp);
289 goto l_again;
290 }
291 }
292 ATENABLE(s, atpgen_lock);
293 atp_timout(atp_rcb_timer, trp_tmo_rcb, 10 * HZ);
294}
295
296atp_iocack(atp, m)
297struct atp_state *atp;
298register gbuf_t *m;
299{
300 if (gbuf_type(m) == MSG_IOCTL)
301 gbuf_set_type(m, MSG_IOCACK);
302 if (gbuf_cont(m))
303 ((ioc_t *)gbuf_rptr(m))->ioc_count = gbuf_msgsize(gbuf_cont(m));
304 else
305 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
306
307 if (atp->dflag)
308 asp_ack_reply(atp->atp_gref, m);
309 else
310 atalk_putnext(atp->atp_gref, m);
311}
312
313atp_iocnak(atp, m, err)
314struct atp_state *atp;
315register gbuf_t *m;
316register int err;
317{
318 if (gbuf_type(m) == MSG_IOCTL)
319 gbuf_set_type(m, MSG_IOCNAK);
320 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
321 ((ioc_t *)gbuf_rptr(m))->ioc_error = err ? err : ENXIO;
322 ((ioc_t *)gbuf_rptr(m))->ioc_rval = -1;
323 if (gbuf_cont(m)) {
324 gbuf_freem(gbuf_cont(m));
325 gbuf_cont(m) = NULL;
326 }
327
328 if (atp->dflag)
329 asp_nak_reply(atp->atp_gref, m);
330 else
331 atalk_putnext(atp->atp_gref, m);
332}
333
334/*
335 * Generate a transaction id for a socket
336 */
337static int lasttid;
338atp_tid(atp)
339register struct atp_state *atp;
340{
341 register int i;
342 register struct atp_trans *trp;
343 int s;
344
345 ATDISABLE(s, atpgen_lock);
346 for (i = lasttid;;) {
347 i = (i+1)&0xffff;
348
349 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
350 if (trp->tr_tid == i)
351 break;
352 }
353 if (trp == NULL) {
354 lasttid = i;
355 ATENABLE(s, atpgen_lock);
356 return(i);
357 }
358 }
359}