]> git.saurik.com Git - apple/xnu.git/blob - bsd/netat/atp_read.c
200577dbf0fd1278b9df764743573eddf3cf7f2a
[apple/xnu.git] / bsd / netat / atp_read.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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
51 static void atp_trans_complete();
52 void atp_x_done();
53 void atp_x_done_funnel();
54 extern 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
61 void atp_treq_event(gref)
62 register gref_t *gref;
63 {
64 register gbuf_t *m;
65 register struct atp_state *atp;
66 boolean_t funnel_state;
67
68 funnel_state = thread_funnel_set(network_flock, TRUE);
69 atp = (struct atp_state *)gref->info;
70 if (atp->dflag)
71 atp = (struct atp_state *)atp->atp_msgq;
72
73 if (atp->dflag) {
74 if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) != NULL) {
75 gbuf_set_type(m, MSG_IOCTL);
76 gbuf_wset(m,sizeof(ioc_t));
77 ((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_GET_POLL;
78 atp_wput(gref, m);
79 }
80 }
81 else if ((m = gbuf_alloc(1, PRI_HI)) != NULL) {
82 *gbuf_rptr(m) = 0;
83 gbuf_wset(m,1);
84 atalk_putnext(gref, m);
85 }
86
87 if (m == 0)
88 timeout(atp_treq_event, gref, 10);
89 (void) thread_funnel_set(network_flock, FALSE);
90 }
91
92 void atp_rput(gref, m)
93 gref_t *gref;
94 gbuf_t *m;
95 {
96 register at_atp_t *athp;
97 register struct atp_state *atp;
98 register int s, s_gen;
99 gbuf_t *m_asp = NULL;
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 */
402 ATDISABLE(s_gen, atpgen_lock);
403 if (rcbp->rc_timestamp) {
404 rcbp->rc_timestamp = time.tv_sec;
405 if (rcbp->rc_timestamp == 0)
406 rcbp->rc_timestamp = 1;
407 }
408 ATENABLE(s_gen, atpgen_lock);
409 rcbp->rc_bitmap = athp->bitmap;
410 rcbp->rc_not_sent_bitmap = athp->bitmap;
411 ATENABLE(s, atp->atp_lock);
412 gbuf_freem(m);
413 atp_reply(rcbp);
414 return;
415
416 case RCB_RELEASED:
417 default:
418 /*
419 * If we have a release or
420 * we haven't sent any data yet
421 * ignore the request
422 */
423 ATENABLE(s, atp->atp_lock);
424 gbuf_freem(m);
425 return;
426 }
427 }
428 ATENABLE(s, atp->atp_lock);
429 return;
430 }
431
432 default:
433 gbuf_freem(m);
434 break;
435 }
436 break;
437
438 case MSG_IOCACK:
439 if (atp->dflag)
440 asp_ack_reply(gref, m);
441 else
442 atalk_putnext(gref, m);
443 break;
444
445 case MSG_IOCNAK:
446 if (atp->dflag)
447 asp_nak_reply(gref, m);
448 else
449 atalk_putnext(gref, m);
450 break;
451
452 default:
453 gbuf_freem(m);
454 }
455 } /* atp_rput */
456
457 void
458 atp_x_done_funnel(trp)
459 register struct atp_trans *trp;
460 {
461 thread_funnel_set(network_flock, TRUE);
462 atp_x_done(trp);
463 (void) thread_funnel_set(network_flock, FALSE);
464
465 }
466
467 void
468 atp_x_done(trp)
469 register struct atp_trans *trp;
470 {
471 struct atp_state *atp;
472 gbuf_t *m;
473
474
475 if ( !trp->tr_xo)
476 atp_trans_complete(trp);
477 else {
478 /*
479 * If execute once send a release
480 */
481 if ((m = (gbuf_t *)atp_build_release(trp)) != NULL) {
482 AT_DDP_HDR(m)->src_socket = ((struct atp_state *)
483 trp->tr_queue)->atp_socket_no;
484 DDP_OUTPUT(m);
485 /*
486 * Now send back the transaction reply to the process
487 * or notify the process if required
488 */
489 atp_trans_complete(trp);
490 } else {
491
492 atp = trp->tr_queue;
493 trp->tr_state = TRANS_RELEASE;
494 timeout(atp_x_done_funnel, trp, 10);
495 }
496 }
497 }
498
499 static void
500 atp_trans_complete(trp)
501 register struct atp_trans *trp;
502 { register gbuf_t *m;
503 register int type;
504 struct atp_state *atp;
505
506 /* we could gbuf_freem(trp->tr_xmt) here if were not planning to
507 re-use the mbuf later */
508 m = trp->tr_xmt;
509 trp->tr_xmt = NULL;
510 trp->tr_state = TRANS_DONE;
511
512 if (gbuf_cont(m) == NULL) /* issued via the new interface */
513 type = AT_ATP_ISSUE_REQUEST_NOTE;
514 else {
515 type = ((ioc_t *)(gbuf_rptr(m)))->ioc_cmd;
516 /*
517 * free any data following the ioctl blk
518 */
519 gbuf_freem(gbuf_cont(m));
520 gbuf_cont(m) = NULL;
521 }
522 dPrintf(D_M_ATP_LOW, D_L_INPUT, ("atp_trans_comp: trp=0x%x type = %s\n",
523 (u_int) trp,
524 (type==AT_ATP_ISSUE_REQUEST)? "AT_ATP_ISSUE_REQUEST":
525 (type==AT_ATP_ISSUE_REQUEST_NOTE)? "AT_ATP_ISSUE_REQUEST_NOTE" :
526 "unknown"));
527
528 switch(type) {
529 case AT_ATP_ISSUE_REQUEST:
530 atp = trp->tr_queue;
531 if (atp->dflag) {
532 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
533 ((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
534 ((ioc_t *)gbuf_rptr(m))->ioc_rval = trp->tr_tid;
535 ((ioc_t *)gbuf_rptr(m))->ioc_cmd = AT_ATP_REQUEST_COMPLETE;
536 gbuf_set_type(m, MSG_IOCTL);
537 atp_rsp_ind(trp, m);
538 } else {
539 if (trp->tr_bdsp == NULL) {
540 gbuf_freem(m);
541 if (trp->tr_rsp_wait)
542 thread_wakeup(&trp->tr_event);
543 } else {
544 gbuf_set_type(m, MSG_IOCACK);
545 ((ioc_t *)gbuf_rptr(m))->ioc_count = 0;
546 ((ioc_t *)gbuf_rptr(m))->ioc_error = 0;
547 ((ioc_t *)gbuf_rptr(m))->ioc_rval = 0;
548 atalk_putnext(trp->tr_queue->atp_gref, m);
549 }
550 }
551 break;
552
553 case AT_ATP_ISSUE_REQUEST_NOTE:
554 gbuf_wset(m,1);
555 *gbuf_rptr(m) = 1;
556 gbuf_set_type(m, MSG_DATA);
557 atalk_putnext(trp->tr_queue->atp_gref, m);
558 break;
559 }
560 } /* atp_trans_complete */