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