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