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