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