]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/atp_read.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / netat / atp_read.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
43866e37
A
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
13 * file.
14 *
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
1c79356b
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
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.
1c79356b
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * Copyright (c) 1996-1998 Apple Computer, Inc.
27 * All Rights Reserved.
28 */
29
30/* Modified for MP, 1996 by Tuyen Nguyen
31 * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
32 */
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>
39#include <sys/proc.h>
40#include <sys/filedesc.h>
41#include <sys/fcntl.h>
42#include <sys/mbuf.h>
43#include <sys/ioctl.h>
44#include <sys/malloc.h>
45#include <sys/socket.h>
46
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>
53
54static void atp_trans_complete();
55void atp_x_done();
55e303ae 56void atp_x_done_funnel(void *);
1c79356b
A
57extern void atp_req_timeout();
58
59/*
60 * Decide what to do about received messages
61 * Version 1.7 of atp_read.c on 89/02/09 17:53:16
62 */
63
55e303ae 64void atp_treq_event(void *arg)
1c79356b 65{
55e303ae 66 register gref_t *gref = (gref_t *)arg;
1c79356b
A
67 register gbuf_t *m;
68 register struct atp_state *atp;
69 boolean_t funnel_state;
70
71 funnel_state = thread_funnel_set(network_flock, TRUE);
72 atp = (struct atp_state *)gref->info;
73 if (atp->dflag)
74 atp = (struct atp_state *)atp->atp_msgq;
75
76 if (atp->dflag) {
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;
81 atp_wput(gref, m);
82 }
83 }
84 else if ((m = gbuf_alloc(1, PRI_HI)) != NULL) {
85 *gbuf_rptr(m) = 0;
86 gbuf_wset(m,1);
87 atalk_putnext(gref, m);
88 }
89
90 if (m == 0)
91 timeout(atp_treq_event, gref, 10);
92 (void) thread_funnel_set(network_flock, FALSE);
93}
94
95void atp_rput(gref, m)
96gref_t *gref;
97gbuf_t *m;
98{
99 register at_atp_t *athp;
100 register struct atp_state *atp;
101 register int s, s_gen;
102 gbuf_t *m_asp = NULL;
103
104 atp = (struct atp_state *)gref->info;
105 if (atp->dflag)
106 atp = (struct atp_state *)atp->atp_msgq;
107
108 switch(gbuf_type(m)) {
109 case MSG_DATA:
110 /*
111 * Decode the message, make sure it is an atp
112 * message
113 */
114 if (((AT_DDP_HDR(m))->type != DDP_ATP) ||
115 (atp->atp_flags & ATP_CLOSING)) {
116 gbuf_freem(m);
117 dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
118 ("atp_rput: dropping MSG, not atp\n"));
119 break;
120 }
121
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",
128 athp->cmd));
129 trace_mbufs(D_M_ATP_LOW, " r", m);
130
131 switch (athp->cmd) {
132
133 case ATP_CMD_TRESP:
134 {
135 register struct atp_trans *trp;
136 register int seqno;
137 register at_ddp_t *ddp;
138
139 /*
140 * we just got a response, find the trans record
141 */
142
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))
146 break;
147 }
148
149 /*
150 * If we can't find one then ignore the message
151 */
152 seqno = athp->bitmap;
153 if (trp == NULL) {
154 ATENABLE(s, atp->atp_lock);
155 ddp = AT_DDP_HDR(m);
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));
160 gbuf_freem(m);
161 return;
162 }
163
164 /*
165 * If no longer valid, drop it
166 */
167 if (trp->tr_state == TRANS_FAILED) {
168 ATENABLE(s, atp->atp_lock);
169 ddp = AT_DDP_HDR(m);
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));
174 gbuf_freem(m);
175 return;
176 }
177
178 /*
179 * If we have already received it, ignore it
180 */
181 if (!(trp->tr_bitmap&atp_mask[seqno]) || trp->tr_rcv[seqno]) {
182 ATENABLE(s, atp->atp_lock);
183 ddp = AT_DDP_HDR(m);
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));
188 gbuf_freem(m);
189 return;
190 }
191
192 /*
193 * Update the received packet bitmap
194 */
195 if (athp->eom)
196 trp->tr_bitmap &= atp_lomask[seqno];
197 else
198 trp->tr_bitmap &= ~atp_mask[seqno];
199
200 /*
201 * Save the message in the trans record
202 */
203 trp->tr_rcv[seqno] = m;
204
205 /*
206 * If it isn't the first message then
207 * can the header
208 */
209 if (seqno)
210 gbuf_rinc(m,DDP_X_HDR_SIZE);
211
212 /*
213 * If we now have all the responses then return
214 * the message to the user
215 */
216 if (trp->tr_bitmap == 0) {
217 ATENABLE(s, atp->atp_lock);
218
219 /*
220 * Cancel the request timer and any
221 * pending transmits
222 */
223 atp_untimout(atp_req_timeout, trp);
224
225 /*
226 * Send the results back to the user
227 */
228 atp_x_done(trp);
229 return;
230 }
231 if (athp->sts) {
232 /*
233 * If they want treq again, send them
234 */
235 ATENABLE(s, atp->atp_lock);
236 atp_untimout(atp_req_timeout, trp);
237 atp_send(trp);
238 return;
239 }
240 ATENABLE(s, atp->atp_lock);
241 return;
242 }
243
244 case ATP_CMD_TREL:
245 { register struct atp_rcb *rcbp;
246 register at_ddp_t *ddp;
247
248 /*
249 * Search for a matching transaction
250 */
251 ddp = AT_DDP_HDR(m);
252
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) {
259 /*
260 * Mark the rcb released
261 */
262 rcbp->rc_not_sent_bitmap = 0;
263 if (rcbp->rc_state == RCB_SENDING)
264 rcbp->rc_state = RCB_RELEASED;
265 else
266 {
267 ddp = 0;
268 atp_rcb_free(rcbp);
269 ATENABLE(s, atp->atp_lock);
270 }
271 break;
272 }
273 }
274
275 if (ddp)
276 ATENABLE(s, atp->atp_lock);
277 gbuf_freem(m);
278 return;
279 }
280
281
282 case ATP_CMD_TREQ:
283 { register struct atp_rcb *rcbp;
284 register at_ddp_t *ddp;
285 gbuf_t *m2;
286
287 /*
288 * If it is a request message, first
289 * check to see
290 * if matches something in our active
291 * request queue
292 */
293 ddp = AT_DDP_HDR(m);
294
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)
301 break;
302 }
303 /*
304 * If this is a new req then do
305 * something with it
306 */
307 if (rcbp == NULL) {
308 /*
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
313 */
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);
321 gbuf_freem(m);
322 dPrintf(D_M_ATP_LOW, D_L_INPUT,
323 ("atp_rput: dropping TREQ, matches req queue\n"));
324 return;
325 }
326 }
327
328 /*
329 * assume someone is interested in
330 * in an asynchronous incoming request
331 */
332 ATENABLE(s, atp->atp_lock);
333 if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
334 gbuf_freem(m);
335 return;
336 }
337 rcbp->rc_state = RCB_UNQUEUED;
338 ATDISABLE(s, atp->atp_lock);
339
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;
349 /*
350 * if async then send it as
351 * data
352 * otherwise, it is a synchronous ioctl so
353 * complete it
354 */
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;
360 m_asp = m2;
361 }
362 } else if ((m2 = gbuf_alloc(1, PRI_HI))) {
363 *gbuf_rptr(m2) = 0;
364 gbuf_wset(m2,1);
365 atalk_putnext(gref, m2);
366 }
367 if (m2 == 0) {
368 dPrintf(D_M_ATP,D_L_WARNING,
369 ("atp_rput: out of buffer for TREQ\n"));
370 timeout(atp_treq_event, gref, 10);
371 }
372 rcbp->rc_ioctl = m;
373
374 /*
375 * move it to the attached list
376 */
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);
381 if (m_asp != NULL) {
382 ATENABLE(s, atp->atp_lock);
383 atp_req_ind(atp, m_asp);
384 return;
385 }
386 } else {
387 dPrintf(D_M_ATP_LOW, D_L_INPUT,
388 ("atp_rput: found match, state:%d\n",
389 rcbp->rc_state));
390
391 /*
392 * Otherwise we have found a matching request
393 * look for what to do
394 */
395 switch (rcbp->rc_state) {
396 case RCB_RESPONDING:
397 case RCB_RESPONSE_FULL:
398 /*
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
403 * the replies
404 */
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;
410 }
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);
415 gbuf_freem(m);
416 atp_reply(rcbp);
417 return;
418
419 case RCB_RELEASED:
420 default:
421 /*
422 * If we have a release or
423 * we haven't sent any data yet
424 * ignore the request
425 */
426 ATENABLE(s, atp->atp_lock);
427 gbuf_freem(m);
428 return;
429 }
430 }
431 ATENABLE(s, atp->atp_lock);
432 return;
433 }
434
435 default:
436 gbuf_freem(m);
437 break;
438 }
439 break;
440
441 case MSG_IOCACK:
442 if (atp->dflag)
443 asp_ack_reply(gref, m);
444 else
445 atalk_putnext(gref, m);
446 break;
447
448 case MSG_IOCNAK:
449 if (atp->dflag)
450 asp_nak_reply(gref, m);
451 else
452 atalk_putnext(gref, m);
453 break;
454
455 default:
456 gbuf_freem(m);
457 }
458} /* atp_rput */
459
460void
461atp_x_done_funnel(trp)
55e303ae 462void *trp;
1c79356b
A
463{
464 thread_funnel_set(network_flock, TRUE);
55e303ae 465 atp_x_done((struct atp_trans *)trp);
1c79356b
A
466 (void) thread_funnel_set(network_flock, FALSE);
467
468}
469
470void
471atp_x_done(trp)
472register struct atp_trans *trp;
473{
474 struct atp_state *atp;
475 gbuf_t *m;
476
477
478 if ( !trp->tr_xo)
479 atp_trans_complete(trp);
480 else {
481 /*
482 * If execute once send a release
483 */
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;
487 DDP_OUTPUT(m);
488 /*
489 * Now send back the transaction reply to the process
490 * or notify the process if required
491 */
492 atp_trans_complete(trp);
493 } else {
494
495 atp = trp->tr_queue;
496 trp->tr_state = TRANS_RELEASE;
497 timeout(atp_x_done_funnel, trp, 10);
498 }
499 }
500}
501
502static void
503atp_trans_complete(trp)
504register struct atp_trans *trp;
505{ register gbuf_t *m;
506 register int type;
507 struct atp_state *atp;
508
509 /* we could gbuf_freem(trp->tr_xmt) here if were not planning to
510 re-use the mbuf later */
511 m = trp->tr_xmt;
512 trp->tr_xmt = NULL;
513 trp->tr_state = TRANS_DONE;
514
515 if (gbuf_cont(m) == NULL) /* issued via the new interface */
516 type = AT_ATP_ISSUE_REQUEST_NOTE;
517 else {
518 type = ((ioc_t *)(gbuf_rptr(m)))->ioc_cmd;
519 /*
520 * free any data following the ioctl blk
521 */
522 gbuf_freem(gbuf_cont(m));
523 gbuf_cont(m) = NULL;
524 }
525 dPrintf(D_M_ATP_LOW, D_L_INPUT, ("atp_trans_comp: trp=0x%x type = %s\n",
526 (u_int) trp,
527 (type==AT_ATP_ISSUE_REQUEST)? "AT_ATP_ISSUE_REQUEST":
528 (type==AT_ATP_ISSUE_REQUEST_NOTE)? "AT_ATP_ISSUE_REQUEST_NOTE" :
529 "unknown"));
530
531 switch(type) {
532 case AT_ATP_ISSUE_REQUEST:
533 atp = trp->tr_queue;
534 if (atp->dflag) {
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);
540 atp_rsp_ind(trp, m);
541 } else {
542 if (trp->tr_bdsp == NULL) {
543 gbuf_freem(m);
544 if (trp->tr_rsp_wait)
9bccf70c 545 wakeup(&trp->tr_event);
1c79356b
A
546 } else {
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);
552 }
553 }
554 break;
555
556 case AT_ATP_ISSUE_REQUEST_NOTE:
557 gbuf_wset(m,1);
558 *gbuf_rptr(m) = 1;
559 gbuf_set_type(m, MSG_DATA);
560 atalk_putnext(trp->tr_queue->atp_gref, m);
561 break;
562 }
563} /* atp_trans_complete */