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