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