]> git.saurik.com Git - apple/xnu.git/blame - bsd/netat/atp_read.c
xnu-792.21.3.tar.gz
[apple/xnu.git] / bsd / netat / atp_read.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
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
57static void atp_trans_complete();
58void atp_x_done();
91447636 59void atp_x_done_locked(void *);
1c79356b
A
60extern void atp_req_timeout();
61
62/*
63 * Decide what to do about received messages
64 * Version 1.7 of atp_read.c on 89/02/09 17:53:16
65 */
66
55e303ae 67void atp_treq_event(void *arg)
1c79356b 68{
55e303ae 69 register gref_t *gref = (gref_t *)arg;
1c79356b
A
70 register gbuf_t *m;
71 register struct atp_state *atp;
1c79356b 72
91447636 73 atalk_lock();
1c79356b
A
74 atp = (struct atp_state *)gref->info;
75 if (atp->dflag)
76 atp = (struct atp_state *)atp->atp_msgq;
77
78 if (atp->dflag) {
79 if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) != NULL) {
80 gbuf_set_type(m, MSG_IOCTL);
81 gbuf_wset(m,sizeof(ioc_t));
82 ((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_GET_POLL;
83 atp_wput(gref, m);
84 }
85 }
86 else if ((m = gbuf_alloc(1, PRI_HI)) != NULL) {
87 *gbuf_rptr(m) = 0;
88 gbuf_wset(m,1);
89 atalk_putnext(gref, m);
90 }
91
92 if (m == 0)
93 timeout(atp_treq_event, gref, 10);
91447636 94 atalk_unlock();
1c79356b
A
95}
96
97void atp_rput(gref, m)
98gref_t *gref;
99gbuf_t *m;
100{
101 register at_atp_t *athp;
102 register struct atp_state *atp;
21362eb3 103 register int s, s_gen;
1c79356b 104 gbuf_t *m_asp = NULL;
91447636 105 struct timeval timenow;
1c79356b
A
106
107 atp = (struct atp_state *)gref->info;
108 if (atp->dflag)
109 atp = (struct atp_state *)atp->atp_msgq;
110
111 switch(gbuf_type(m)) {
112 case MSG_DATA:
113 /*
114 * Decode the message, make sure it is an atp
115 * message
116 */
117 if (((AT_DDP_HDR(m))->type != DDP_ATP) ||
118 (atp->atp_flags & ATP_CLOSING)) {
119 gbuf_freem(m);
120 dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
121 ("atp_rput: dropping MSG, not atp\n"));
122 break;
123 }
124
125 athp = AT_ATP_HDR(m);
126 dPrintf(D_M_ATP_LOW, D_L_INPUT,
127 ("atp_rput MSG_DATA: %s (%d)\n",
128 (athp->cmd == ATP_CMD_TRESP)? "TRESP":
129 (athp->cmd == ATP_CMD_TREL)? "TREL":
130 (athp->cmd == ATP_CMD_TREQ)? "TREQ": "unknown",
131 athp->cmd));
132 trace_mbufs(D_M_ATP_LOW, " r", m);
133
134 switch (athp->cmd) {
135
136 case ATP_CMD_TRESP:
137 {
138 register struct atp_trans *trp;
139 register int seqno;
21362eb3 140 register at_ddp_t *ddp;
1c79356b
A
141
142 /*
143 * we just got a response, find the trans record
144 */
145
21362eb3 146 ATDISABLE(s, atp->atp_lock);
1c79356b 147 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
21362eb3 148 if (trp->tr_tid == UAS_VALUE(athp->tid))
1c79356b
A
149 break;
150 }
151
152 /*
153 * If we can't find one then ignore the message
154 */
155 seqno = athp->bitmap;
156 if (trp == NULL) {
21362eb3 157 ATENABLE(s, atp->atp_lock);
1c79356b
A
158 ddp = AT_DDP_HDR(m);
159 dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
160 ("atp_rput: dropping TRESP, no trp,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
21362eb3
A
161 UAS_VALUE(athp->tid),
162 ddp->dst_socket,ddp->src_node,ddp->src_socket,seqno));
1c79356b
A
163 gbuf_freem(m);
164 return;
165 }
166
167 /*
168 * If no longer valid, drop it
169 */
170 if (trp->tr_state == TRANS_FAILED) {
21362eb3 171 ATENABLE(s, atp->atp_lock);
1c79356b
A
172 ddp = AT_DDP_HDR(m);
173 dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
174 ("atp_rput: dropping TRESP, failed trp,tid=%d,loc=%d,rem=%d.%d\n",
21362eb3 175 UAS_VALUE(athp->tid),
1c79356b
A
176 ddp->dst_socket, ddp->src_node, ddp->src_socket));
177 gbuf_freem(m);
178 return;
179 }
180
181 /*
182 * If we have already received it, ignore it
183 */
184 if (!(trp->tr_bitmap&atp_mask[seqno]) || trp->tr_rcv[seqno]) {
21362eb3 185 ATENABLE(s, atp->atp_lock);
1c79356b
A
186 ddp = AT_DDP_HDR(m);
187 dPrintf(D_M_ATP_LOW, (D_L_INPUT|D_L_ERROR),
188 ("atp_rput: dropping TRESP, duplicate,tid=%d,loc=%d,rem=%d.%d,seqno=%d\n",
21362eb3 189 UAS_VALUE(athp->tid),
1c79356b
A
190 ddp->dst_socket, ddp->src_node, ddp->src_socket, seqno));
191 gbuf_freem(m);
192 return;
193 }
194
195 /*
196 * Update the received packet bitmap
197 */
198 if (athp->eom)
199 trp->tr_bitmap &= atp_lomask[seqno];
200 else
201 trp->tr_bitmap &= ~atp_mask[seqno];
202
203 /*
204 * Save the message in the trans record
205 */
206 trp->tr_rcv[seqno] = m;
207
208 /*
209 * If it isn't the first message then
210 * can the header
211 */
212 if (seqno)
213 gbuf_rinc(m,DDP_X_HDR_SIZE);
214
215 /*
216 * If we now have all the responses then return
217 * the message to the user
218 */
219 if (trp->tr_bitmap == 0) {
21362eb3 220 ATENABLE(s, atp->atp_lock);
1c79356b
A
221
222 /*
223 * Cancel the request timer and any
224 * pending transmits
225 */
226 atp_untimout(atp_req_timeout, trp);
227
228 /*
229 * Send the results back to the user
230 */
231 atp_x_done(trp);
232 return;
233 }
234 if (athp->sts) {
235 /*
236 * If they want treq again, send them
237 */
21362eb3 238 ATENABLE(s, atp->atp_lock);
1c79356b
A
239 atp_untimout(atp_req_timeout, trp);
240 atp_send(trp);
241 return;
242 }
21362eb3 243 ATENABLE(s, atp->atp_lock);
1c79356b
A
244 return;
245 }
246
247 case ATP_CMD_TREL:
248 { register struct atp_rcb *rcbp;
249 register at_ddp_t *ddp;
250
251 /*
252 * Search for a matching transaction
253 */
254 ddp = AT_DDP_HDR(m);
255
21362eb3 256 ATDISABLE(s, atp->atp_lock);
1c79356b 257 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
21362eb3 258 if (rcbp->rc_tid == UAS_VALUE(athp->tid) &&
1c79356b
A
259 rcbp->rc_socket.node == ddp->src_node &&
260 rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
261 rcbp->rc_socket.socket == ddp->src_socket) {
262 /*
263 * Mark the rcb released
264 */
265 rcbp->rc_not_sent_bitmap = 0;
266 if (rcbp->rc_state == RCB_SENDING)
267 rcbp->rc_state = RCB_RELEASED;
268 else
269 {
270 ddp = 0;
271 atp_rcb_free(rcbp);
21362eb3 272 ATENABLE(s, atp->atp_lock);
1c79356b
A
273 }
274 break;
275 }
276 }
277
21362eb3
A
278 if (ddp)
279 ATENABLE(s, atp->atp_lock);
1c79356b
A
280 gbuf_freem(m);
281 return;
282 }
283
284
285 case ATP_CMD_TREQ:
286 { register struct atp_rcb *rcbp;
287 register at_ddp_t *ddp;
288 gbuf_t *m2;
289
290 /*
291 * If it is a request message, first
292 * check to see
293 * if matches something in our active
294 * request queue
295 */
296 ddp = AT_DDP_HDR(m);
297
21362eb3 298 ATDISABLE(s, atp->atp_lock);
1c79356b 299 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
21362eb3 300 if (rcbp->rc_tid == UAS_VALUE(athp->tid) &&
1c79356b
A
301 rcbp->rc_socket.node == ddp->src_node &&
302 rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
303 rcbp->rc_socket.socket == ddp->src_socket)
304 break;
305 }
306 /*
307 * If this is a new req then do
308 * something with it
309 */
310 if (rcbp == NULL) {
311 /*
312 * see if it matches something in the
313 * attached request queue
314 * if it does, just release the message
315 * and go on about our buisness
316 */
317 /* we just did this, why do again? -jjs 4-10-95 */
318 for (rcbp = atp->atp_attached.head; rcbp; rcbp = rcbp->rc_list.next) {
21362eb3 319 if (rcbp->rc_tid == UAS_VALUE(athp->tid) &&
1c79356b
A
320 rcbp->rc_socket.node == ddp->src_node &&
321 rcbp->rc_socket.net == NET_VALUE(ddp->src_net) &&
322 rcbp->rc_socket.socket == ddp->src_socket) {
21362eb3 323 ATENABLE(s, atp->atp_lock);
1c79356b
A
324 gbuf_freem(m);
325 dPrintf(D_M_ATP_LOW, D_L_INPUT,
326 ("atp_rput: dropping TREQ, matches req queue\n"));
327 return;
328 }
329 }
330
331 /*
332 * assume someone is interested in
333 * in an asynchronous incoming request
334 */
21362eb3 335 ATENABLE(s, atp->atp_lock);
1c79356b
A
336 if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
337 gbuf_freem(m);
338 return;
339 }
340 rcbp->rc_state = RCB_UNQUEUED;
21362eb3 341 ATDISABLE(s, atp->atp_lock);
1c79356b
A
342
343 rcbp->rc_local_node = ddp->dst_node;
21362eb3 344 NET_NET(rcbp->rc_local_net, ddp->dst_net);
1c79356b
A
345 rcbp->rc_socket.socket = ddp->src_socket;
346 rcbp->rc_socket.node = ddp->src_node;
347 rcbp->rc_socket.net = NET_VALUE(ddp->src_net);
21362eb3 348 rcbp->rc_tid = UAS_VALUE(athp->tid);
1c79356b
A
349 rcbp->rc_bitmap = athp->bitmap;
350 rcbp->rc_not_sent_bitmap = athp->bitmap;
351 rcbp->rc_xo = athp->xo;
352 /*
353 * if async then send it as
354 * data
355 * otherwise, it is a synchronous ioctl so
356 * complete it
357 */
358 if (atp->dflag) { /* for ASP? */
359 if ((m2 = gbuf_alloc(sizeof(ioc_t), PRI_HI))) {
360 gbuf_set_type(m2, MSG_DATA);
361 gbuf_wset(m2,sizeof(ioc_t));
362 ((ioc_t *)gbuf_rptr(m2))->ioc_cmd = AT_ATP_GET_POLL;
363 m_asp = m2;
364 }
365 } else if ((m2 = gbuf_alloc(1, PRI_HI))) {
366 *gbuf_rptr(m2) = 0;
367 gbuf_wset(m2,1);
368 atalk_putnext(gref, m2);
369 }
370 if (m2 == 0) {
371 dPrintf(D_M_ATP,D_L_WARNING,
372 ("atp_rput: out of buffer for TREQ\n"));
373 timeout(atp_treq_event, gref, 10);
374 }
375 rcbp->rc_ioctl = m;
376
377 /*
378 * move it to the attached list
379 */
380 dPrintf(D_M_ATP_LOW, D_L_INPUT,
381 ("atp_rput: moving to attached list\n"));
382 rcbp->rc_state = RCB_PENDING;
383 ATP_Q_APPEND(atp->atp_attached, rcbp, rc_list);
384 if (m_asp != NULL) {
21362eb3 385 ATENABLE(s, atp->atp_lock);
1c79356b
A
386 atp_req_ind(atp, m_asp);
387 return;
388 }
389 } else {
390 dPrintf(D_M_ATP_LOW, D_L_INPUT,
391 ("atp_rput: found match, state:%d\n",
392 rcbp->rc_state));
393
394 /*
395 * Otherwise we have found a matching request
396 * look for what to do
397 */
398 switch (rcbp->rc_state) {
399 case RCB_RESPONDING:
400 case RCB_RESPONSE_FULL:
401 /*
402 * If it is one we have in progress
403 * (either have all the responses
404 * or are waiting for them)
405 * update the bitmap and resend
406 * the replies
407 */
91447636 408 getmicrouptime(&timenow);
21362eb3 409 ATDISABLE(s_gen, atpgen_lock);
1c79356b 410 if (rcbp->rc_timestamp) {
91447636 411 rcbp->rc_timestamp = timenow.tv_sec;
1c79356b
A
412 if (rcbp->rc_timestamp == 0)
413 rcbp->rc_timestamp = 1;
414 }
21362eb3 415 ATENABLE(s_gen, atpgen_lock);
1c79356b
A
416 rcbp->rc_bitmap = athp->bitmap;
417 rcbp->rc_not_sent_bitmap = athp->bitmap;
21362eb3 418 ATENABLE(s, atp->atp_lock);
1c79356b
A
419 gbuf_freem(m);
420 atp_reply(rcbp);
421 return;
422
423 case RCB_RELEASED:
424 default:
425 /*
426 * If we have a release or
427 * we haven't sent any data yet
428 * ignore the request
429 */
21362eb3 430 ATENABLE(s, atp->atp_lock);
1c79356b
A
431 gbuf_freem(m);
432 return;
433 }
434 }
21362eb3 435 ATENABLE(s, atp->atp_lock);
1c79356b
A
436 return;
437 }
438
439 default:
440 gbuf_freem(m);
441 break;
442 }
443 break;
444
445 case MSG_IOCACK:
446 if (atp->dflag)
447 asp_ack_reply(gref, m);
448 else
449 atalk_putnext(gref, m);
450 break;
451
452 case MSG_IOCNAK:
453 if (atp->dflag)
454 asp_nak_reply(gref, m);
455 else
456 atalk_putnext(gref, m);
457 break;
458
459 default:
460 gbuf_freem(m);
461 }
462} /* atp_rput */
463
464void
91447636 465atp_x_done_locked(trp)
55e303ae 466void *trp;
1c79356b 467{
91447636 468 atalk_lock();
55e303ae 469 atp_x_done((struct atp_trans *)trp);
91447636 470 atalk_unlock();
1c79356b
A
471
472}
473
474void
475atp_x_done(trp)
476register struct atp_trans *trp;
477{
478 struct atp_state *atp;
479 gbuf_t *m;
480
481
482 if ( !trp->tr_xo)
483 atp_trans_complete(trp);
484 else {
485 /*
486 * If execute once send a release
487 */
488 if ((m = (gbuf_t *)atp_build_release(trp)) != NULL) {
489 AT_DDP_HDR(m)->src_socket = ((struct atp_state *)
490 trp->tr_queue)->atp_socket_no;
491 DDP_OUTPUT(m);
492 /*
493 * Now send back the transaction reply to the process
494 * or notify the process if required
495 */
496 atp_trans_complete(trp);
497 } else {
498
499 atp = trp->tr_queue;
500 trp->tr_state = TRANS_RELEASE;
91447636 501 timeout(atp_x_done_locked, trp, 10);
1c79356b
A
502 }
503 }
504}
505
506static void
507atp_trans_complete(trp)
508register struct atp_trans *trp;
509{ register gbuf_t *m;
510 register int type;
511 struct atp_state *atp;
512
513 /* we could gbuf_freem(trp->tr_xmt) here if were not planning to
514 re-use the mbuf later */
515 m = trp->tr_xmt;
516 trp->tr_xmt = NULL;
517 trp->tr_state = TRANS_DONE;
518
519 if (gbuf_cont(m) == NULL) /* issued via the new interface */
520 type = AT_ATP_ISSUE_REQUEST_NOTE;
521 else {
522 type = ((ioc_t *)(gbuf_rptr(m)))->ioc_cmd;
523 /*
524 * free any data following the ioctl blk
525 */
526 gbuf_freem(gbuf_cont(m));
527 gbuf_cont(m) = NULL;
528 }
529 dPrintf(D_M_ATP_LOW, D_L_INPUT, ("atp_trans_comp: trp=0x%x type = %s\n",
530 (u_int) trp,
531 (type==AT_ATP_ISSUE_REQUEST)? "AT_ATP_ISSUE_REQUEST":
532 (type==AT_ATP_ISSUE_REQUEST_NOTE)? "AT_ATP_ISSUE_REQUEST_NOTE" :
533 "unknown"));
534
535 switch(type) {
536 case AT_ATP_ISSUE_REQUEST:
537 atp = trp->tr_queue;
538 if (atp->dflag) {
539 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
540 ((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
541 ((ioc_t *)gbuf_rptr(m))->ioc_rval = trp->tr_tid;
542 ((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_REQUEST_COMPLETE;
543 gbuf_set_type(m, MSG_IOCTL);
544 atp_rsp_ind(trp, m);
545 } else {
546 if (trp->tr_bdsp == NULL) {
547 gbuf_freem(m);
548 if (trp->tr_rsp_wait)
9bccf70c 549 wakeup(&trp->tr_event);
1c79356b
A
550 } else {
551 gbuf_set_type(m, MSG_IOCACK);
552 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
553 ((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
554 ((ioc_t *)gbuf_rptr(m))->ioc_rval = 0;
555 atalk_putnext(trp->tr_queue->atp_gref, m);
556 }
557 }
558 break;
559
560 case AT_ATP_ISSUE_REQUEST_NOTE:
561 gbuf_wset(m,1);
562 *gbuf_rptr(m) = 1;
563 gbuf_set_type(m, MSG_DATA);
564 atalk_putnext(trp->tr_queue->atp_gref, m);
565 break;
566 }
567} /* atp_trans_complete */