2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * Copyright (c) 1996-1998 Apple Computer, Inc.
30 * All Rights Reserved.
33 /* Modified for MP, 1996 by Tuyen Nguyen
34 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
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>
43 #include <sys/filedesc.h>
44 #include <sys/fcntl.h>
46 #include <sys/ioctl.h>
47 #include <sys/malloc.h>
48 #include <sys/socket.h>
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>
57 extern atlock_t atpgen_lock
;
59 void atp_send(struct atp_trans
*);
62 * The request timer retries a request, if all retries are used up
68 register struct atp_trans
*trp
;
73 struct atp_state
*atp
;
74 struct atp_trans
*ctrp
;
76 if ((atp
= trp
->tr_queue
) == 0)
78 ATDISABLE(s
, atp
->atp_lock
);
79 if (atp
->atp_flags
& ATP_CLOSING
) {
80 ATENABLE(s
, atp
->atp_lock
);
83 for (ctrp
= atp
->atp_trans_wait
.head
; ctrp
; ctrp
= ctrp
->tr_list
.next
) {
88 ATENABLE(s
, atp
->atp_lock
);
92 if ((m
= gbuf_cont(trp
->tr_xmt
)) == NULL
)
93 m
= trp
->tr_xmt
; /* issued via the new interface */
95 if (trp
->tr_retry
== 0) {
96 trp
->tr_state
= TRANS_FAILED
;
97 if (m
== trp
->tr_xmt
) {
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
);
109 dPrintf(D_M_ATP_LOW
,D_L_INFO
, ("atp_req_timeout: skt=%d\n",
110 trp
->tr_local_socket
));
112 switch(((ioc_t
*)(gbuf_rptr(trp
->tr_xmt
)))->ioc_cmd
) {
113 case AT_ATP_ISSUE_REQUEST
:
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
);
120 if (trp
->tr_rsp_wait
)
121 wakeup(&trp
->tr_event
);
124 ATENABLE(s
, atp
->atp_lock
);
125 atp_iocnak(trp
->tr_queue
, m
, ETIMEDOUT
);
129 case AT_ATP_ISSUE_REQUEST_NOTE
:
130 case AT_ATP_ISSUE_REQUEST_TICKLE
:
131 trp
->tr_xmt
= gbuf_cont(m
);
136 (AT_ATP_HDR(m
))->bitmap
= trp
->tr_bitmap
;
138 if (trp
->tr_retry
!= (unsigned int) ATP_INFINITE_RETRIES
)
140 ATENABLE(s
, atp
->atp_lock
);
147 * atp_free frees up a request, cleaning up the queues and freeing
149 * always called at 'lock'
153 register struct atp_trans
*trp
;
155 register struct atp_state
*atp
;
159 dPrintf(D_M_ATP_LOW
, D_L_TRACE
,
160 ("atp_free: freeing trp 0x%x\n", (u_int
) trp
));
162 ATDISABLE(s
, atpgen_lock
);
164 if (trp
->tr_state
== TRANS_ABORTING
) {
165 ATP_Q_REMOVE(atp_trans_abort
, trp
, tr_list
);
166 trp
->tr_state
= TRANS_DONE
;
169 if (trp
->tr_tmo_func
)
170 atp_untimout(atp_req_timeout
, trp
);
173 ATP_Q_REMOVE(atp
->atp_trans_wait
, trp
, tr_list
);
176 gbuf_freem(trp
->tr_xmt
);
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
;
186 gbuf_freem(trp
->tr_bdsp
);
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
);
199 ATENABLE(s
, atpgen_lock
);
205 * atp_send transmits a request packet by queuing it (if it isn't already) and
206 * scheduling the queue
210 register struct atp_trans
*trp
;
213 struct atp_state
*atp
;
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
));
218 if ((atp
= trp
->tr_queue
) != 0) {
219 if (trp
->tr_state
== TRANS_TIMEOUT
) {
220 if ((m
= gbuf_cont(trp
->tr_xmt
)) == NULL
)
224 * Now either release the transaction or start the timer
226 if (!trp
->tr_retry
&& !trp
->tr_bitmap
&& !trp
->tr_xo
) {
227 m
= (gbuf_t
*)gbuf_copym(m
);
230 m
= (gbuf_t
*)gbuf_dupm(m
);
232 atp_timout(atp_req_timeout
, trp
, trp
->tr_timeout
);
236 trace_mbufs(D_M_ATP_LOW
, " m", m
);
245 * atp_reply sends all the available messages in the bitmap again
246 * by queueing us to the write service routine
250 register struct atp_rcb
*rcbp
;
252 register struct atp_state
*atp
;
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
])
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
);
270 ATENABLE(s
, atp
->atp_lock
);
276 * The rcb timer just frees the rcb, this happens when we missed a release for XO
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
;
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
;
294 if (abs(timenow
.tv_sec
- rcbp
->rc_timestamp
) > 30) {
295 ATENABLE(s
, atpgen_lock
);
300 ATENABLE(s
, atpgen_lock
);
301 atp_timout(atp_rcb_timer
, trp_tmo_rcb
, 10 * HZ
);
305 struct atp_state
*atp
;
308 if (gbuf_type(m
) == MSG_IOCTL
)
309 gbuf_set_type(m
, MSG_IOCACK
);
311 ((ioc_t
*)gbuf_rptr(m
))->ioc_count
= gbuf_msgsize(gbuf_cont(m
));
313 ((ioc_t
*)gbuf_rptr(m
))->ioc_count
= 0;
316 asp_ack_reply(atp
->atp_gref
, m
);
318 atalk_putnext(atp
->atp_gref
, m
);
321 atp_iocnak(atp
, m
, err
)
322 struct atp_state
*atp
;
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;
332 gbuf_freem(gbuf_cont(m
));
337 asp_nak_reply(atp
->atp_gref
, m
);
339 atalk_putnext(atp
->atp_gref
, m
);
343 * Generate a transaction id for a socket
347 register struct atp_state
*atp
;
350 register struct atp_trans
*trp
;
353 ATDISABLE(s
, atpgen_lock
);
354 for (i
= lasttid
;;) {
357 for (trp
= atp
->atp_trans_wait
.head
; trp
; trp
= trp
->tr_list
.next
) {
358 if (trp
->tr_tid
== i
)
363 ATENABLE(s
, atpgen_lock
);