2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1996-1998 Apple Computer, Inc.
24 * All Rights Reserved.
27 /* Modified for MP, 1996 by Tuyen Nguyen
28 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
30 #include <sys/errno.h>
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <machine/spl.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
37 #include <sys/filedesc.h>
38 #include <sys/fcntl.h>
40 #include <sys/ioctl.h>
41 #include <sys/malloc.h>
42 #include <sys/socket.h>
44 #include <netat/sysglue.h>
45 #include <netat/appletalk.h>
46 #include <netat/ddp.h>
47 #include <netat/at_pcb.h>
48 #include <netat/atp.h>
49 #include <netat/debug.h>
51 static void atp_trans_complete();
53 void atp_x_done_funnel();
54 extern void atp_req_timeout();
57 * Decide what to do about received messages
58 * Version 1.7 of atp_read.c on 89/02/09 17:53:16
61 void atp_treq_event(gref
)
62 register gref_t
*gref
;
65 register struct atp_state
*atp
;
66 boolean_t funnel_state
;
68 funnel_state
= thread_funnel_set(network_flock
, TRUE
);
69 atp
= (struct atp_state
*)gref
->info
;
71 atp
= (struct atp_state
*)atp
->atp_msgq
;
74 if ((m
= gbuf_alloc(sizeof(ioc_t
), PRI_HI
)) != NULL
) {
75 gbuf_set_type(m
, MSG_IOCTL
);
76 gbuf_wset(m
,sizeof(ioc_t
));
77 ((ioc_t
*)gbuf_rptr(m
))->ioc_cmd
= AT_ATP_GET_POLL
;
81 else if ((m
= gbuf_alloc(1, PRI_HI
)) != NULL
) {
84 atalk_putnext(gref
, m
);
88 timeout(atp_treq_event
, gref
, 10);
89 (void) thread_funnel_set(network_flock
, FALSE
);
92 void atp_rput(gref
, m
)
96 register at_atp_t
*athp
;
97 register struct atp_state
*atp
;
98 register int s
, s_gen
;
101 atp
= (struct atp_state
*)gref
->info
;
103 atp
= (struct atp_state
*)atp
->atp_msgq
;
105 switch(gbuf_type(m
)) {
108 * Decode the message, make sure it is an atp
111 if (((AT_DDP_HDR(m
))->type
!= DDP_ATP
) ||
112 (atp
->atp_flags
& ATP_CLOSING
)) {
114 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
115 ("atp_rput: dropping MSG, not atp\n"));
119 athp
= AT_ATP_HDR(m
);
120 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
121 ("atp_rput MSG_DATA: %s (%d)\n",
122 (athp
->cmd
== ATP_CMD_TRESP
)? "TRESP":
123 (athp
->cmd
== ATP_CMD_TREL
)? "TREL":
124 (athp
->cmd
== ATP_CMD_TREQ
)? "TREQ": "unknown",
126 trace_mbufs(D_M_ATP_LOW
, " r", m
);
132 register struct atp_trans
*trp
;
134 register at_ddp_t
*ddp
;
137 * we just got a response, find the trans record
140 ATDISABLE(s
, atp
->atp_lock
);
141 for (trp
= atp
->atp_trans_wait
.head
; trp
; trp
= trp
->tr_list
.next
) {
142 if (trp
->tr_tid
== UAS_VALUE(athp
->tid
))
147 * If we can't find one then ignore the message
149 seqno
= athp
->bitmap
;
151 ATENABLE(s
, atp
->atp_lock
);
153 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
154 ("atp_rput: dropping TRESP, no trp,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
155 UAS_VALUE(athp
->tid
),
156 ddp
->dst_socket
,ddp
->src_node
,ddp
->src_socket
,seqno
));
162 * If no longer valid, drop it
164 if (trp
->tr_state
== TRANS_FAILED
) {
165 ATENABLE(s
, atp
->atp_lock
);
167 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
168 ("atp_rput: dropping TRESP, failed trp,tid=%d,loc=%d,rem=%d.%d\n",
169 UAS_VALUE(athp
->tid
),
170 ddp
->dst_socket
, ddp
->src_node
, ddp
->src_socket
));
176 * If we have already received it, ignore it
178 if (!(trp
->tr_bitmap
&atp_mask
[seqno
]) || trp
->tr_rcv
[seqno
]) {
179 ATENABLE(s
, atp
->atp_lock
);
181 dPrintf(D_M_ATP_LOW
, (D_L_INPUT
|D_L_ERROR
),
182 ("atp_rput: dropping TRESP, duplicate,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
183 UAS_VALUE(athp
->tid
),
184 ddp
->dst_socket
, ddp
->src_node
, ddp
->src_socket
, seqno
));
190 * Update the received packet bitmap
193 trp
->tr_bitmap
&= atp_lomask
[seqno
];
195 trp
->tr_bitmap
&= ~atp_mask
[seqno
];
198 * Save the message in the trans record
200 trp
->tr_rcv
[seqno
] = m
;
203 * If it isn't the first message then
207 gbuf_rinc(m
,DDP_X_HDR_SIZE
);
210 * If we now have all the responses then return
211 * the message to the user
213 if (trp
->tr_bitmap
== 0) {
214 ATENABLE(s
, atp
->atp_lock
);
217 * Cancel the request timer and any
220 atp_untimout(atp_req_timeout
, trp
);
223 * Send the results back to the user
230 * If they want treq again, send them
232 ATENABLE(s
, atp
->atp_lock
);
233 atp_untimout(atp_req_timeout
, trp
);
237 ATENABLE(s
, atp
->atp_lock
);
242 { register struct atp_rcb
*rcbp
;
243 register at_ddp_t
*ddp
;
246 * Search for a matching transaction
250 ATDISABLE(s
, atp
->atp_lock
);
251 for (rcbp
= atp
->atp_rcb
.head
; rcbp
; rcbp
= rcbp
->rc_list
.next
) {
252 if (rcbp
->rc_tid
== UAS_VALUE(athp
->tid
) &&
253 rcbp
->rc_socket
.node
== ddp
->src_node
&&
254 rcbp
->rc_socket
.net
== NET_VALUE(ddp
->src_net
) &&
255 rcbp
->rc_socket
.socket
== ddp
->src_socket
) {
257 * Mark the rcb released
259 rcbp
->rc_not_sent_bitmap
= 0;
260 if (rcbp
->rc_state
== RCB_SENDING
)
261 rcbp
->rc_state
= RCB_RELEASED
;
266 ATENABLE(s
, atp
->atp_lock
);
273 ATENABLE(s
, atp
->atp_lock
);
280 { register struct atp_rcb
*rcbp
;
281 register at_ddp_t
*ddp
;
285 * If it is a request message, first
287 * if matches something in our active
292 ATDISABLE(s
, atp
->atp_lock
);
293 for (rcbp
= atp
->atp_rcb
.head
; rcbp
; rcbp
= rcbp
->rc_list
.next
) {
294 if (rcbp
->rc_tid
== UAS_VALUE(athp
->tid
) &&
295 rcbp
->rc_socket
.node
== ddp
->src_node
&&
296 rcbp
->rc_socket
.net
== NET_VALUE(ddp
->src_net
) &&
297 rcbp
->rc_socket
.socket
== ddp
->src_socket
)
301 * If this is a new req then do
306 * see if it matches something in the
307 * attached request queue
308 * if it does, just release the message
309 * and go on about our buisness
311 /* we just did this, why do again? -jjs 4-10-95 */
312 for (rcbp
= atp
->atp_attached
.head
; rcbp
; rcbp
= rcbp
->rc_list
.next
) {
313 if (rcbp
->rc_tid
== UAS_VALUE(athp
->tid
) &&
314 rcbp
->rc_socket
.node
== ddp
->src_node
&&
315 rcbp
->rc_socket
.net
== NET_VALUE(ddp
->src_net
) &&
316 rcbp
->rc_socket
.socket
== ddp
->src_socket
) {
317 ATENABLE(s
, atp
->atp_lock
);
319 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
320 ("atp_rput: dropping TREQ, matches req queue\n"));
326 * assume someone is interested in
327 * in an asynchronous incoming request
329 ATENABLE(s
, atp
->atp_lock
);
330 if ((rcbp
= atp_rcb_alloc(atp
)) == NULL
) {
334 rcbp
->rc_state
= RCB_UNQUEUED
;
335 ATDISABLE(s
, atp
->atp_lock
);
337 rcbp
->rc_local_node
= ddp
->dst_node
;
338 NET_NET(rcbp
->rc_local_net
, ddp
->dst_net
);
339 rcbp
->rc_socket
.socket
= ddp
->src_socket
;
340 rcbp
->rc_socket
.node
= ddp
->src_node
;
341 rcbp
->rc_socket
.net
= NET_VALUE(ddp
->src_net
);
342 rcbp
->rc_tid
= UAS_VALUE(athp
->tid
);
343 rcbp
->rc_bitmap
= athp
->bitmap
;
344 rcbp
->rc_not_sent_bitmap
= athp
->bitmap
;
345 rcbp
->rc_xo
= athp
->xo
;
347 * if async then send it as
349 * otherwise, it is a synchronous ioctl so
352 if (atp
->dflag
) { /* for ASP? */
353 if ((m2
= gbuf_alloc(sizeof(ioc_t
), PRI_HI
))) {
354 gbuf_set_type(m2
, MSG_DATA
);
355 gbuf_wset(m2
,sizeof(ioc_t
));
356 ((ioc_t
*)gbuf_rptr(m2
))->ioc_cmd
= AT_ATP_GET_POLL
;
359 } else if ((m2
= gbuf_alloc(1, PRI_HI
))) {
362 atalk_putnext(gref
, m2
);
365 dPrintf(D_M_ATP
,D_L_WARNING
,
366 ("atp_rput: out of buffer for TREQ\n"));
367 timeout(atp_treq_event
, gref
, 10);
372 * move it to the attached list
374 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
375 ("atp_rput: moving to attached list\n"));
376 rcbp
->rc_state
= RCB_PENDING
;
377 ATP_Q_APPEND(atp
->atp_attached
, rcbp
, rc_list
);
379 ATENABLE(s
, atp
->atp_lock
);
380 atp_req_ind(atp
, m_asp
);
384 dPrintf(D_M_ATP_LOW
, D_L_INPUT
,
385 ("atp_rput: found match, state:%d\n",
389 * Otherwise we have found a matching request
390 * look for what to do
392 switch (rcbp
->rc_state
) {
394 case RCB_RESPONSE_FULL
:
396 * If it is one we have in progress
397 * (either have all the responses
398 * or are waiting for them)
399 * update the bitmap and resend
402 ATDISABLE(s_gen
, atpgen_lock
);
403 if (rcbp
->rc_timestamp
) {
404 rcbp
->rc_timestamp
= time
.tv_sec
;
405 if (rcbp
->rc_timestamp
== 0)
406 rcbp
->rc_timestamp
= 1;
408 ATENABLE(s_gen
, atpgen_lock
);
409 rcbp
->rc_bitmap
= athp
->bitmap
;
410 rcbp
->rc_not_sent_bitmap
= athp
->bitmap
;
411 ATENABLE(s
, atp
->atp_lock
);
419 * If we have a release or
420 * we haven't sent any data yet
423 ATENABLE(s
, atp
->atp_lock
);
428 ATENABLE(s
, atp
->atp_lock
);
440 asp_ack_reply(gref
, m
);
442 atalk_putnext(gref
, m
);
447 asp_nak_reply(gref
, m
);
449 atalk_putnext(gref
, m
);
458 atp_x_done_funnel(trp
)
459 register struct atp_trans
*trp
;
461 thread_funnel_set(network_flock
, TRUE
);
463 (void) thread_funnel_set(network_flock
, FALSE
);
469 register struct atp_trans
*trp
;
471 struct atp_state
*atp
;
476 atp_trans_complete(trp
);
479 * If execute once send a release
481 if ((m
= (gbuf_t
*)atp_build_release(trp
)) != NULL
) {
482 AT_DDP_HDR(m
)->src_socket
= ((struct atp_state
*)
483 trp
->tr_queue
)->atp_socket_no
;
486 * Now send back the transaction reply to the process
487 * or notify the process if required
489 atp_trans_complete(trp
);
493 trp
->tr_state
= TRANS_RELEASE
;
494 timeout(atp_x_done_funnel
, trp
, 10);
500 atp_trans_complete(trp
)
501 register struct atp_trans
*trp
;
502 { register gbuf_t
*m
;
504 struct atp_state
*atp
;
506 /* we could gbuf_freem(trp->tr_xmt) here if were not planning to
507 re-use the mbuf later */
510 trp
->tr_state
= TRANS_DONE
;
512 if (gbuf_cont(m
) == NULL
) /* issued via the new interface */
513 type
= AT_ATP_ISSUE_REQUEST_NOTE
;
515 type
= ((ioc_t
*)(gbuf_rptr(m
)))->ioc_cmd
;
517 * free any data following the ioctl blk
519 gbuf_freem(gbuf_cont(m
));
522 dPrintf(D_M_ATP_LOW
, D_L_INPUT
, ("atp_trans_comp: trp=0x%x type = %s\n",
524 (type
==AT_ATP_ISSUE_REQUEST
)? "AT_ATP_ISSUE_REQUEST":
525 (type
==AT_ATP_ISSUE_REQUEST_NOTE
)? "AT_ATP_ISSUE_REQUEST_NOTE" :
529 case AT_ATP_ISSUE_REQUEST
:
532 ((ioc_t
*)gbuf_rptr(m
))->ioc_count
= 0;
533 ((ioc_t
*)gbuf_rptr(m
))->ioc_error
= 0;
534 ((ioc_t
*)gbuf_rptr(m
))->ioc_rval
= trp
->tr_tid
;
535 ((ioc_t
*)gbuf_rptr(m
))->ioc_cmd
= AT_ATP_REQUEST_COMPLETE
;
536 gbuf_set_type(m
, MSG_IOCTL
);
539 if (trp
->tr_bdsp
== NULL
) {
541 if (trp
->tr_rsp_wait
)
542 thread_wakeup(&trp
->tr_event
);
544 gbuf_set_type(m
, MSG_IOCACK
);
545 ((ioc_t
*)gbuf_rptr(m
))->ioc_count
= 0;
546 ((ioc_t
*)gbuf_rptr(m
))->ioc_error
= 0;
547 ((ioc_t
*)gbuf_rptr(m
))->ioc_rval
= 0;
548 atalk_putnext(trp
->tr_queue
->atp_gref
, m
);
553 case AT_ATP_ISSUE_REQUEST_NOTE
:
556 gbuf_set_type(m
, MSG_DATA
);
557 atalk_putnext(trp
->tr_queue
->atp_gref
, m
);
560 } /* atp_trans_complete */