]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
e5568f75 A |
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. | |
1c79356b | 11 | * |
e5568f75 A |
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 | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
e5568f75 A |
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. | |
1c79356b A |
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(); | |
55e303ae | 53 | void atp_x_done_funnel(void *); |
1c79356b A |
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 | ||
55e303ae | 61 | void atp_treq_event(void *arg) |
1c79356b | 62 | { |
55e303ae | 63 | register gref_t *gref = (gref_t *)arg; |
1c79356b A |
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) | |
55e303ae | 459 | void *trp; |
1c79356b A |
460 | { |
461 | thread_funnel_set(network_flock, TRUE); | |
55e303ae | 462 | atp_x_done((struct atp_trans *)trp); |
1c79356b A |
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) | |
9bccf70c | 542 | wakeup(&trp->tr_event); |
1c79356b A |
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 */ |