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