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