2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1996-1998 Apple Computer, Inc.
27 * All Rights Reserved.
30 /* Modified for MP, 1996 by Tuyen Nguyen
31 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
33 #include <sys/errno.h>
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <machine/spl.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
40 #include <sys/filedesc.h>
41 #include <sys/fcntl.h>
43 #include <sys/ioctl.h>
44 #include <sys/malloc.h>
45 #include <sys/socket.h>
47 #include <netat/sysglue.h>
48 #include <netat/appletalk.h>
49 #include <netat/ddp.h>
50 #include <netat/at_pcb.h>
51 #include <netat/atp.h>
52 #include <netat/debug.h>
54 static void atp_trans_complete();
56 void atp_x_done_funnel(void *);
57 extern void atp_req_timeout();
60 * Decide what to do about received messages
61 * Version 1.7 of atp_read.c on 89/02/09 17:53:16
64 void atp_treq_event(void *arg
)
66 register gref_t
*gref
= (gref_t
*)arg
;
68 register struct atp_state
*atp
;
69 boolean_t funnel_state
;
71 funnel_state
= thread_funnel_set(network_flock
, TRUE
);
72 atp
= (struct atp_state
*)gref
->info
;
74 atp
= (struct atp_state
*)atp
->atp_msgq
;
77 if ((m
= gbuf_alloc(sizeof(ioc_t
), PRI_HI
)) != NULL
) {
78 gbuf_set_type(m
, MSG_IOCTL
);
79 gbuf_wset(m
,sizeof(ioc_t
));
80 ((ioc_t
*)gbuf_rptr(m
))->ioc_cmd
= AT_ATP_GET_POLL
;
84 else if ((m
= gbuf_alloc(1, PRI_HI
)) != NULL
) {
87 atalk_putnext(gref
, m
);
91 timeout(atp_treq_event
, gref
, 10);
92 (void) thread_funnel_set(network_flock
, FALSE
);
95 void atp_rput(gref
, m
)
99 register at_atp_t
*athp
;
100 register struct atp_state
*atp
;
101 register int s
, s_gen
;
102 gbuf_t
*m_asp
= NULL
;
104 atp
= (struct atp_state
*)gref
->info
;
106 atp
= (struct atp_state
*)atp
->atp_msgq
;
108 switch(gbuf_type(m
)) {
111 * Decode the message, make sure it is an atp
114 if (((AT_DDP_HDR(m
))->type
!= DDP_ATP
) ||
115 (atp
->atp_flags
& ATP_CLOSING
)) {
117 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
118 ("atp_rput: dropping MSG, not atp\n"));
122 athp
= AT_ATP_HDR(m
);
123 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
124 ("atp_rput MSG_DATA: %s (%d)\n",
125 (athp
->cmd
== ATP_CMD_TRESP
)? "TRESP":
126 (athp
->cmd
== ATP_CMD_TREL
)? "TREL":
127 (athp
->cmd
== ATP_CMD_TREQ
)? "TREQ": "unknown",
129 trace_mbufs(D_M_ATP_LOW
, " r", m
);
135 register struct atp_trans
*trp
;
137 register at_ddp_t
*ddp
;
140 * we just got a response, find the trans record
143 ATDISABLE(s
, atp
->atp_lock
);
144 for (trp
= atp
->atp_trans_wait
.head
; trp
; trp
= trp
->tr_list
.next
) {
145 if (trp
->tr_tid
== UAS_VALUE(athp
->tid
))
150 * If we can't find one then ignore the message
152 seqno
= athp
->bitmap
;
154 ATENABLE(s
, atp
->atp_lock
);
156 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
157 ("atp_rput: dropping TRESP, no trp,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
158 UAS_VALUE(athp
->tid
),
159 ddp
->dst_socket
,ddp
->src_node
,ddp
->src_socket
,seqno
));
165 * If no longer valid, drop it
167 if (trp
->tr_state
== TRANS_FAILED
) {
168 ATENABLE(s
, atp
->atp_lock
);
170 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
171 ("atp_rput: dropping TRESP, failed trp,tid=%d,loc=%d,rem=%d.%d\n",
172 UAS_VALUE(athp
->tid
),
173 ddp
->dst_socket
, ddp
->src_node
, ddp
->src_socket
));
179 * If we have already received it, ignore it
181 if (!(trp
->tr_bitmap
&atp_mask
[seqno
]) || trp
->tr_rcv
[seqno
]) {
182 ATENABLE(s
, atp
->atp_lock
);
184 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
185 ("atp_rput: dropping TRESP, duplicate,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
186 UAS_VALUE(athp
->tid
),
187 ddp
->dst_socket
, ddp
->src_node
, ddp
->src_socket
, seqno
));
193 * Update the received packet bitmap
196 trp
->tr_bitmap
&= atp_lomask
[seqno
];
198 trp
->tr_bitmap
&= ~atp_mask
[seqno
];
201 * Save the message in the trans record
203 trp
->tr_rcv
[seqno
] = m
;
206 * If it isn't the first message then
210 gbuf_rinc(m
,DDP_X_HDR_SIZE
);
213 * If we now have all the responses then return
214 * the message to the user
216 if (trp
->tr_bitmap
== 0) {
217 ATENABLE(s
, atp
->atp_lock
);
220 * Cancel the request timer and any
223 atp_untimout(atp_req_timeout
, trp
);
226 * Send the results back to the user
233 * If they want treq again, send them
235 ATENABLE(s
, atp
->atp_lock
);
236 atp_untimout(atp_req_timeout
, trp
);
240 ATENABLE(s
, atp
->atp_lock
);
245 { register struct atp_rcb
*rcbp
;
246 register at_ddp_t
*ddp
;
249 * Search for a matching transaction
253 ATDISABLE(s
, atp
->atp_lock
);
254 for (rcbp
= atp
->atp_rcb
.head
; rcbp
; rcbp
= rcbp
->rc_list
.next
) {
255 if (rcbp
->rc_tid
== UAS_VALUE(athp
->tid
) &&
256 rcbp
->rc_socket
.node
== ddp
->src_node
&&
257 rcbp
->rc_socket
.net
== NET_VALUE(ddp
->src_net
) &&
258 rcbp
->rc_socket
.socket
== ddp
->src_socket
) {
260 * Mark the rcb released
262 rcbp
->rc_not_sent_bitmap
= 0;
263 if (rcbp
->rc_state
== RCB_SENDING
)
264 rcbp
->rc_state
= RCB_RELEASED
;
269 ATENABLE(s
, atp
->atp_lock
);
276 ATENABLE(s
, atp
->atp_lock
);
283 { register struct atp_rcb
*rcbp
;
284 register at_ddp_t
*ddp
;
288 * If it is a request message, first
290 * if matches something in our active
295 ATDISABLE(s
, atp
->atp_lock
);
296 for (rcbp
= atp
->atp_rcb
.head
; rcbp
; rcbp
= rcbp
->rc_list
.next
) {
297 if (rcbp
->rc_tid
== UAS_VALUE(athp
->tid
) &&
298 rcbp
->rc_socket
.node
== ddp
->src_node
&&
299 rcbp
->rc_socket
.net
== NET_VALUE(ddp
->src_net
) &&
300 rcbp
->rc_socket
.socket
== ddp
->src_socket
)
304 * If this is a new req then do
309 * see if it matches something in the
310 * attached request queue
311 * if it does, just release the message
312 * and go on about our buisness
314 /* we just did this, why do again? -jjs 4-10-95 */
315 for (rcbp
= atp
->atp_attached
.head
; rcbp
; rcbp
= rcbp
->rc_list
.next
) {
316 if (rcbp
->rc_tid
== UAS_VALUE(athp
->tid
) &&
317 rcbp
->rc_socket
.node
== ddp
->src_node
&&
318 rcbp
->rc_socket
.net
== NET_VALUE(ddp
->src_net
) &&
319 rcbp
->rc_socket
.socket
== ddp
->src_socket
) {
320 ATENABLE(s
, atp
->atp_lock
);
322 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
323 ("atp_rput: dropping TREQ, matches req queue\n"));
329 * assume someone is interested in
330 * in an asynchronous incoming request
332 ATENABLE(s
, atp
->atp_lock
);
333 if ((rcbp
= atp_rcb_alloc(atp
)) == NULL
) {
337 rcbp
->rc_state
= RCB_UNQUEUED
;
338 ATDISABLE(s
, atp
->atp_lock
);
340 rcbp
->rc_local_node
= ddp
->dst_node
;
341 NET_NET(rcbp
->rc_local_net
, ddp
->dst_net
);
342 rcbp
->rc_socket
.socket
= ddp
->src_socket
;
343 rcbp
->rc_socket
.node
= ddp
->src_node
;
344 rcbp
->rc_socket
.net
= NET_VALUE(ddp
->src_net
);
345 rcbp
->rc_tid
= UAS_VALUE(athp
->tid
);
346 rcbp
->rc_bitmap
= athp
->bitmap
;
347 rcbp
->rc_not_sent_bitmap
= athp
->bitmap
;
348 rcbp
->rc_xo
= athp
->xo
;
350 * if async then send it as
352 * otherwise, it is a synchronous ioctl so
355 if (atp
->dflag
) { /* for ASP? */
356 if ((m2
= gbuf_alloc(sizeof(ioc_t
), PRI_HI
))) {
357 gbuf_set_type(m2
, MSG_DATA
);
358 gbuf_wset(m2
,sizeof(ioc_t
));
359 ((ioc_t
*)gbuf_rptr(m2
))->ioc_cmd
= AT_ATP_GET_POLL
;
362 } else if ((m2
= gbuf_alloc(1, PRI_HI
))) {
365 atalk_putnext(gref
, m2
);
368 dPrintf(D_M_ATP
,D_L_WARNING
,
369 ("atp_rput: out of buffer for TREQ\n"));
370 timeout(atp_treq_event
, gref
, 10);
375 * move it to the attached list
377 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
378 ("atp_rput: moving to attached list\n"));
379 rcbp
->rc_state
= RCB_PENDING
;
380 ATP_Q_APPEND(atp
->atp_attached
, rcbp
, rc_list
);
382 ATENABLE(s
, atp
->atp_lock
);
383 atp_req_ind(atp
, m_asp
);
387 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
388 ("atp_rput: found match, state:%d\n",
392 * Otherwise we have found a matching request
393 * look for what to do
395 switch (rcbp
->rc_state
) {
397 case RCB_RESPONSE_FULL
:
399 * If it is one we have in progress
400 * (either have all the responses
401 * or are waiting for them)
402 * update the bitmap and resend
405 ATDISABLE(s_gen
, atpgen_lock
);
406 if (rcbp
->rc_timestamp
) {
407 rcbp
->rc_timestamp
= time
.tv_sec
;
408 if (rcbp
->rc_timestamp
== 0)
409 rcbp
->rc_timestamp
= 1;
411 ATENABLE(s_gen
, atpgen_lock
);
412 rcbp
->rc_bitmap
= athp
->bitmap
;
413 rcbp
->rc_not_sent_bitmap
= athp
->bitmap
;
414 ATENABLE(s
, atp
->atp_lock
);
422 * If we have a release or
423 * we haven't sent any data yet
426 ATENABLE(s
, atp
->atp_lock
);
431 ATENABLE(s
, atp
->atp_lock
);
443 asp_ack_reply(gref
, m
);
445 atalk_putnext(gref
, m
);
450 asp_nak_reply(gref
, m
);
452 atalk_putnext(gref
, m
);
461 atp_x_done_funnel(trp
)
464 thread_funnel_set(network_flock
, TRUE
);
465 atp_x_done((struct atp_trans
*)trp
);
466 (void) thread_funnel_set(network_flock
, FALSE
);
472 register struct atp_trans
*trp
;
474 struct atp_state
*atp
;
479 atp_trans_complete(trp
);
482 * If execute once send a release
484 if ((m
= (gbuf_t
*)atp_build_release(trp
)) != NULL
) {
485 AT_DDP_HDR(m
)->src_socket
= ((struct atp_state
*)
486 trp
->tr_queue
)->atp_socket_no
;
489 * Now send back the transaction reply to the process
490 * or notify the process if required
492 atp_trans_complete(trp
);
496 trp
->tr_state
= TRANS_RELEASE
;
497 timeout(atp_x_done_funnel
, trp
, 10);
503 atp_trans_complete(trp
)
504 register struct atp_trans
*trp
;
505 { register gbuf_t
*m
;
507 struct atp_state
*atp
;
509 /* we could gbuf_freem(trp->tr_xmt) here if were not planning to
510 re-use the mbuf later */
513 trp
->tr_state
= TRANS_DONE
;
515 if (gbuf_cont(m
) == NULL
) /* issued via the new interface */
516 type
= AT_ATP_ISSUE_REQUEST_NOTE
;
518 type
= ((ioc_t
*)(gbuf_rptr(m
)))->ioc_cmd
;
520 * free any data following the ioctl blk
522 gbuf_freem(gbuf_cont(m
));
525 dPrintf(D_M_ATP_LOW
, D_L_INPUT
, ("atp_trans_comp: trp=0x%x type = %s\n",
527 (type
==AT_ATP_ISSUE_REQUEST
)? "AT_ATP_ISSUE_REQUEST":
528 (type
==AT_ATP_ISSUE_REQUEST_NOTE
)? "AT_ATP_ISSUE_REQUEST_NOTE" :
532 case AT_ATP_ISSUE_REQUEST
:
535 ((ioc_t
*)gbuf_rptr(m
))->ioc_count
= 0;
536 ((ioc_t
*)gbuf_rptr(m
))->ioc_error
= 0;
537 ((ioc_t
*)gbuf_rptr(m
))->ioc_rval
= trp
->tr_tid
;
538 ((ioc_t
*)gbuf_rptr(m
))->ioc_cmd
= AT_ATP_REQUEST_COMPLETE
;
539 gbuf_set_type(m
, MSG_IOCTL
);
542 if (trp
->tr_bdsp
== NULL
) {
544 if (trp
->tr_rsp_wait
)
545 wakeup(&trp
->tr_event
);
547 gbuf_set_type(m
, MSG_IOCACK
);
548 ((ioc_t
*)gbuf_rptr(m
))->ioc_count
= 0;
549 ((ioc_t
*)gbuf_rptr(m
))->ioc_error
= 0;
550 ((ioc_t
*)gbuf_rptr(m
))->ioc_rval
= 0;
551 atalk_putnext(trp
->tr_queue
->atp_gref
, m
);
556 case AT_ATP_ISSUE_REQUEST_NOTE
:
559 gbuf_set_type(m
, MSG_DATA
);
560 atalk_putnext(trp
->tr_queue
->atp_gref
, m
);
563 } /* atp_trans_complete */