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