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