]> git.saurik.com Git - apple/xnu.git/blob - bsd/netat/atp_write.c
ae3c5bb29c8084cabaf0a205c2d56a2d176bf914
[apple/xnu.git] / bsd / netat / atp_write.c
1 /*
2 * Copyright (c) 2000 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 #define RESOLVE_DBG
39
40 #include <sys/errno.h>
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <machine/spl.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/proc.h>
47 #include <sys/filedesc.h>
48 #include <sys/fcntl.h>
49 #include <kern/locks.h>
50 #include <sys/mbuf.h>
51 #include <sys/ioctl.h>
52 #include <sys/malloc.h>
53 #include <sys/socket.h>
54 #include <sys/socketvar.h>
55
56 #include <net/if.h>
57
58 #include <netat/sysglue.h>
59 #include <netat/appletalk.h>
60 #include <netat/ddp.h>
61 #include <netat/at_pcb.h>
62 #include <netat/atp.h>
63 #include <netat/at_var.h>
64 #include <netat/asp.h>
65 #include <netat/at_pat.h>
66 #include <netat/debug.h>
67
68 static int loop_cnt; /* for debugging loops */
69 #define CHK_LOOP(str) { \
70 if (loop_cnt++ > 100) { \
71 kprintf("%s", str); \
72 break; \
73 } \
74 }
75
76 static int atp_pack_bdsp(struct atp_trans *, struct atpBDS *);
77 static int atp_unpack_bdsp(struct atp_state *, gbuf_t *, struct atp_rcb *,
78 int, int);
79 void atp_trp_clock(), asp_clock(), asp_clock_locked(), atp_trp_clock_locked();;
80
81 extern struct atp_rcb_qhead atp_need_rel;
82 extern int atp_inited;
83 extern struct atp_state *atp_used_list;
84 extern asp_scb_t *scb_free_list;
85
86 extern gbuf_t *scb_resource_m;
87 extern gbuf_t *atp_resource_m;
88 extern gref_t *atp_inputQ[];
89 extern int atp_pidM[];
90 extern at_ifaddr_t *ifID_home;
91 extern lck_mtx_t * atalk_mutex;
92
93 static struct atp_trans *trp_tmo_list;
94 struct atp_trans *trp_tmo_rcb;
95
96 /* first bds entry gives number of bds entries in total (hack) */
97 #define get_bds_entries(m) \
98 ((gbuf_len(m) > TOTAL_ATP_HDR_SIZE)? \
99 (UAS_VALUE(((struct atpBDS *)(AT_ATP_HDR(m)->data))->bdsDataSz)): 0)
100
101 #define atpBDSsize (sizeof(struct atpBDS)*ATP_TRESP_MAX)
102
103 void atp_link()
104 {
105 trp_tmo_list = 0;
106 trp_tmo_rcb = atp_trans_alloc(0);
107 atp_timout(atp_rcb_timer, trp_tmo_rcb, 10 * HZ);
108 atp_trp_clock((void *)&atp_inited);
109 asp_clock((void *)&atp_inited);
110 }
111
112 void atp_unlink()
113 {
114 untimeout(asp_clock_locked, (void *)&atp_inited);
115 untimeout(atp_trp_clock_locked, (void *)&atp_inited);
116 atp_untimout(atp_rcb_timer, trp_tmo_rcb);
117 trp_tmo_list = 0;
118
119 #ifdef BAD_IDEA
120 /* allocated in asp_scb_alloc(), which is called
121 by asp_open() */
122 if (scb_resource_m) {
123 gbuf_freem(scb_resource_m);
124 scb_resource_m = 0;
125 scb_free_list = 0;
126 }
127 /* allocated in atp_trans_alloc() */
128 if (atp_resource_m) {
129 gbuf_freem(atp_resource_m);
130 atp_resource_m = 0;
131 atp_trans_free_list = 0;
132 }
133 #endif
134 }
135
136 /*
137 * write queue put routine .... filter out other than IOCTLs
138 * Version 1.8 of atp_write.c on 89/02/09 17:53:26
139 */
140
141 void
142 atp_wput(gref, m)
143 register gref_t *gref;
144 register gbuf_t *m;
145 {
146 register ioc_t *iocbp;
147 int i, xcnt;
148 struct atp_state *atp;
149 struct atp_trans *trp;
150 struct atp_rcb *rcbp;
151 at_socket skt;
152
153 atp = (struct atp_state *)gref->info;
154 if (atp->dflag)
155 atp = (struct atp_state *)atp->atp_msgq;
156
157 switch(gbuf_type(m)) {
158 case MSG_DATA:
159 if (atp->atp_msgq) {
160 gbuf_freem(m);
161 dPrintf(D_M_ATP, D_L_WARNING,
162 ("atp_wput: atp_msgq discarded\n"));
163 } else
164 atp->atp_msgq = m;
165 break;
166
167 case MSG_IOCTL:
168 /* Need to ensure that all copyin/copyout calls are made at
169 * put routine time which should be in the user context. (true when
170 * we are the stream head). The service routine can be called on an
171 * unpredictable context and copyin/copyout calls will get wrong results
172 * or even panic the kernel.
173 */
174 iocbp = (ioc_t *)gbuf_rptr(m);
175
176 switch (iocbp->ioc_cmd) {
177 case AT_ATP_BIND_REQ:
178 if (gbuf_cont(m) == NULL) {
179 iocbp->ioc_rval = -1;
180 atp_iocnak(atp, m, EINVAL);
181 return;
182 }
183 skt = *(at_socket *)gbuf_rptr(gbuf_cont(m));
184 if ((skt = (at_socket)atp_bind(gref, (unsigned int)skt, 0)) == 0)
185 atp_iocnak(atp, m, EINVAL);
186 else {
187 *(at_socket *)gbuf_rptr(gbuf_cont(m)) = skt;
188 iocbp->ioc_rval = 0;
189 atp_iocack(atp, m);
190 atp_dequeue_atp(atp);
191 }
192 return;
193
194 case AT_ATP_GET_CHANID:
195 if (gbuf_cont(m) == NULL) {
196 iocbp->ioc_rval = -1;
197 atp_iocnak(atp, m, EINVAL);
198 return;
199 }
200 *(gref_t **)gbuf_rptr(gbuf_cont(m)) = gref;
201 atp_iocack(atp, m);
202 return;
203
204 /* not the close and not the tickle(?) */
205 case AT_ATP_ISSUE_REQUEST_DEF:
206 case AT_ATP_ISSUE_REQUEST_DEF_NOTE: {
207 gbuf_t *bds, *tmp, *m2;
208 struct atp_rcb *rcbp;
209 at_ddp_t *ddp;
210 at_atp_t *athp;
211
212 if ((tmp = gbuf_cont(m)) != 0) {
213 if ((bds = gbuf_dupb(tmp)) == NULL) {
214 atp_iocnak(atp, m, ENOBUFS);
215 return;
216 }
217 gbuf_rinc(tmp,atpBDSsize);
218 gbuf_wset(bds,atpBDSsize);
219 iocbp->ioc_count -= atpBDSsize;
220 gbuf_cont(tmp) = bds;
221 }
222
223 /*
224 * send a response to a transaction
225 * first check it out
226 */
227 if (iocbp->ioc_count < TOTAL_ATP_HDR_SIZE) {
228 atp_iocnak(atp, m, EINVAL);
229 break;
230 }
231
232 /*
233 * remove the response from the message
234 */
235 m2 = gbuf_cont(m);
236 gbuf_cont(m) = NULL;
237 iocbp->ioc_count = 0;
238 ddp = AT_DDP_HDR(m2);
239 athp = AT_ATP_HDR(m2);
240 if (atp->atp_msgq) {
241 gbuf_cont(m2) = atp->atp_msgq;
242 atp->atp_msgq = 0;
243 }
244
245 /*
246 * search for the corresponding rcb
247 */
248 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
249 if (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid) &&
250 rcbp->rc_socket.node == ddp->dst_node &&
251 rcbp->rc_socket.net == NET_VALUE(ddp->dst_net) &&
252 rcbp->rc_socket.socket == ddp->dst_socket)
253 break;
254 }
255
256 /*
257 * If it has already been sent then return an error
258 */
259 if ((rcbp && rcbp->rc_state != RCB_NOTIFIED) ||
260 (rcbp == NULL && athp->xo)) {
261 atp_iocnak(atp, m, ENOENT);
262 gbuf_freem(m2);
263 return;
264 }
265 if (rcbp == NULL) { /* a response for an ALO transaction */
266 if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
267 atp_iocnak(atp, m, ENOBUFS);
268 gbuf_freem(m2);
269 return;
270 }
271 rcbp->rc_ioctl = 0;
272 rcbp->rc_socket.socket = ddp->dst_socket;
273 rcbp->rc_socket.node = ddp->dst_node;
274 rcbp->rc_socket.net = NET_VALUE(ddp->dst_net);
275 rcbp->rc_tid = UAS_VALUE_NTOH(athp->tid);
276 rcbp->rc_bitmap = 0xff;
277 rcbp->rc_xo = 0;
278 rcbp->rc_state = RCB_SENDING;
279 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
280 }
281 xcnt = get_bds_entries(m2);
282 if ((i = atp_unpack_bdsp(atp, m2, rcbp, xcnt, FALSE))) {
283 if ( !rcbp->rc_xo)
284 atp_rcb_free(rcbp);
285 atp_iocnak(atp, m, i);
286 return;
287 }
288 atp_send_replies(atp, rcbp);
289
290 /*
291 * send the ack back to the responder
292 */
293 atp_iocack(atp, m);
294 return;
295 }
296
297 case AT_ATP_GET_POLL: {
298 if (gbuf_cont(m)) {
299 gbuf_freem(gbuf_cont(m));
300 gbuf_cont(m) = NULL;
301 iocbp->ioc_count = 0;
302 }
303
304 /*
305 * search for a waiting request
306 */
307 if ((rcbp = atp->atp_attached.head)) {
308 /*
309 * Got one, move it to the active response Q
310 */
311 gbuf_cont(m) = rcbp->rc_ioctl;
312 rcbp->rc_ioctl = NULL;
313 if (rcbp->rc_xo) {
314 ATP_Q_REMOVE(atp->atp_attached, rcbp, rc_list);
315 rcbp->rc_state = RCB_NOTIFIED;
316 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
317 } else {
318 /* detach rcbp from attached queue,
319 * and free any outstanding resources
320 */
321 atp_rcb_free(rcbp);
322 }
323 atp_iocack(atp, m);
324 } else {
325 /*
326 * None available - can out
327 */
328 atp_iocnak(atp, m, EAGAIN);
329 }
330 break;
331 }
332
333 case AT_ATP_CANCEL_REQUEST: {
334 /*
335 * Cancel a pending request
336 */
337 if (iocbp->ioc_count != sizeof(int)) {
338 atp_iocnak(atp, m, EINVAL);
339 break;
340 }
341 i = *(int *)gbuf_rptr(gbuf_cont(m));
342 gbuf_freem(gbuf_cont(m));
343 gbuf_cont(m) = NULL;
344 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
345 if (trp->tr_tid == i)
346 break;
347 }
348 if (trp == NULL)
349 atp_iocnak(atp, m, ENOENT);
350 else {
351 atp_free(trp);
352 atp_iocack(atp, m);
353 }
354 break;
355 }
356
357 case AT_ATP_PEEK: {
358 unsigned char event;
359 if (atalk_peek(gref, &event) == -1)
360 atp_iocnak(atp, m, EAGAIN);
361 else {
362 *gbuf_rptr(gbuf_cont(m)) = event;
363 atp_iocack(atp, m);
364 }
365 break;
366 }
367
368 case DDP_IOC_GET_CFG:
369 #ifdef APPLETALK_DEBUG
370 kprintf("atp_wput: DDP_IOC_GET_CFG\n");
371 #endif
372 if (gbuf_cont(m) == 0) {
373 atp_iocnak(atp, m, EINVAL);
374 break;
375 }
376 {
377 /* *** was ddp_get_cfg() *** */
378 ddp_addr_t *cfgp =
379 (ddp_addr_t *)gbuf_rptr(gbuf_cont(m));
380 cfgp->inet.net = ifID_home->ifThisNode.s_net;
381 cfgp->inet.node = ifID_home->ifThisNode.s_node;
382 cfgp->inet.socket = atp->atp_socket_no;
383 cfgp->ddptype = DDP_ATP;
384 #ifdef NOT_YET
385 cfgp->inet.net = atp->atp_gref->laddr.s_net;
386 cfgp->inet.node = atp->atp_gref->laddr.s_node;
387 cfgp->inet.socket = atp->atp_gref->lport;
388 cfgp->ddptype = atp->atp_gref->ddptype;
389 #endif
390 }
391 gbuf_wset(gbuf_cont(m), sizeof(ddp_addr_t));
392 atp_iocack(atp, m);
393 break;
394
395 default:
396 /*
397 * Otherwise pass it on, if possible
398 */
399 iocbp->ioc_private = (void *)gref;
400 DDP_OUTPUT(m);
401 break;
402 }
403 break;
404
405 default:
406 gbuf_freem(m);
407 break;
408 }
409 } /* atp_wput */
410
411 gbuf_t *atp_build_release(trp)
412 register struct atp_trans *trp;
413 {
414 register gbuf_t *m;
415 register at_ddp_t *ddp;
416 register at_atp_t *athp;
417
418 /*
419 * Now try and allocate enough space to send the message
420 * if none is available the caller will schedule
421 * a timeout so we can retry for more space soon
422 */
423 if ((m = (gbuf_t *)gbuf_alloc(AT_WR_OFFSET+ATP_HDR_SIZE, PRI_HI)) != NULL) {
424 gbuf_rinc(m,AT_WR_OFFSET);
425 gbuf_wset(m,TOTAL_ATP_HDR_SIZE);
426 ddp = AT_DDP_HDR(m);
427 ddp->type = DDP_ATP;
428 UAS_ASSIGN_HTON(ddp->checksum, 0);
429 ddp->dst_socket = trp->tr_socket.socket;
430 ddp->dst_node = trp->tr_socket.node;
431 NET_ASSIGN(ddp->dst_net, trp->tr_socket.net);
432 ddp->src_node = trp->tr_local_node;
433 NET_NET(ddp->src_net, trp->tr_local_net);
434
435 /*
436 * clear the cmd/xo/eom/sts/unused fields
437 */
438 athp = AT_ATP_HDR(m);
439 ATP_CLEAR_CONTROL(athp);
440 athp->cmd = ATP_CMD_TREL;
441 UAS_ASSIGN_HTON(athp->tid, trp->tr_tid);
442 }
443
444 return (m);
445 }
446
447 void atp_send_replies(atp, rcbp)
448 register struct atp_state *atp;
449 register struct atp_rcb *rcbp;
450 { register gbuf_t *m;
451 register int i, len;
452 int s_gen, cnt, err, offset, space;
453 unsigned char *m0_rptr = NULL, *m0_wptr = NULL;
454 register at_atp_t *athp;
455 register struct atpBDS *bdsp;
456 register gbuf_t *m2, *m1, *m0, *mhdr;
457 caddr_t lastPage;
458 gbuf_t *mprev, *mlist = 0;
459 at_socket src_socket = (at_socket)atp->atp_socket_no;
460 gbuf_t *rc_xmt[ATP_TRESP_MAX];
461 struct ddp_atp {
462 char ddp_atp_hdr[TOTAL_ATP_HDR_SIZE];
463 };
464 struct timeval timenow;
465
466 if (rcbp->rc_queue != atp)
467 return;
468 if (rcbp->rc_not_sent_bitmap == 0)
469 goto nothing_to_send;
470
471 dPrintf(D_M_ATP_LOW, D_L_OUTPUT, ("atp_send_replies\n"));
472 /*
473 * Do this for each message that hasn't been sent
474 */
475 cnt = rcbp->rc_pktcnt;
476 for (i = 0; i < cnt; i++) {
477 rc_xmt[i] = 0;
478 if (rcbp->rc_snd[i]) {
479 if ((rc_xmt[i] =
480 gbuf_alloc(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE,PRI_MED))
481 == NULL) {
482 for (cnt = 0; cnt < i; cnt++)
483 if (rc_xmt[cnt])
484 gbuf_freeb(rc_xmt[cnt]);
485 goto nothing_to_send;
486 }
487 }
488 }
489
490 m = rcbp->rc_xmt;
491 m0 = gbuf_cont(m);
492 if (gbuf_len(m) > TOTAL_ATP_HDR_SIZE)
493 bdsp = (struct atpBDS *)(AT_ATP_HDR(m)->data);
494 else
495 bdsp = 0;
496 offset = 0;
497 if (m0)
498 space = gbuf_msgsize(m0);
499 else
500 space = 0;
501 for (i = 0; i < cnt; i++) {
502 if (rcbp->rc_snd[i] == 0) {
503 if ((len = UAS_VALUE(bdsp->bdsBuffSz))) {
504 offset += len;
505 space -= len;
506 }
507 } else {
508 mhdr = rc_xmt[i];
509 /* setup header fields */
510 gbuf_rinc(mhdr,AT_WR_OFFSET);
511 gbuf_wset(mhdr,TOTAL_ATP_HDR_SIZE);
512 *(struct ddp_atp *)(gbuf_rptr(mhdr))= *(struct ddp_atp *)(gbuf_rptr(m));
513 athp = AT_ATP_HDR(mhdr);
514 ATP_CLEAR_CONTROL(athp);
515 athp->cmd = ATP_CMD_TRESP;
516 athp->bitmap = i;
517 if (i == (cnt - 1))
518 athp->eom = 1; /* for the last fragment */
519 if (bdsp) {
520 UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
521 if ((len = UAS_VALUE(bdsp->bdsBuffSz)) && m0 != 0 && space > 0) {
522 if ((m1 = m_copym(m0, offset, len, M_DONTWAIT)) == 0) {
523 for (i = 0; i < cnt; i++)
524 if (rc_xmt[i])
525 gbuf_freem(rc_xmt[i]);
526 goto nothing_to_send;
527 }
528 offset += len;
529 space -= len;
530 gbuf_cont(mhdr) = m1;
531 }
532 }
533
534 AT_DDP_HDR(mhdr)->src_socket = src_socket;
535 dPrintf(D_M_ATP_LOW, D_L_OUTPUT,
536 ("atp_send_replies: %d, socket=%d, size=%d\n",
537 i, atp->atp_socket_no, gbuf_msgsize(gbuf_cont(m2))));
538
539 if (mlist)
540 gbuf_next(mprev) = mhdr;
541 else
542 mlist = mhdr;
543 mprev = mhdr;
544
545 rcbp->rc_snd[i] = 0;
546 rcbp->rc_not_sent_bitmap &= ~atp_mask[i];
547 if (rcbp->rc_not_sent_bitmap == 0)
548 break;
549 }
550 /*
551 * on to the next frag
552 */
553 bdsp++;
554 }
555 if (mlist)
556 DDP_OUTPUT(mlist);
557
558
559 nothing_to_send:
560 /*
561 * If all replies from this reply block have been sent then
562 * remove it from the queue and mark it so
563 */
564 if (rcbp->rc_queue != atp)
565 return;
566 rcbp->rc_rep_waiting = 0;
567
568 /*
569 * If we are doing execute once re-set the rcb timeout
570 * each time we send back any part of the response. Note
571 * that this timer is started when an initial request is
572 * received. Each response reprimes the timer. Duplicate
573 * requests do not reprime the timer.
574 *
575 * We have sent all of a response so free the
576 * resources.
577 */
578 if (rcbp->rc_xo && rcbp->rc_state != RCB_RELEASED) {
579 getmicrouptime(&timenow);
580 if (rcbp->rc_timestamp == 0) {
581 rcbp->rc_timestamp = timenow.tv_sec;
582 if (rcbp->rc_timestamp == 0)
583 rcbp->rc_timestamp = 1;
584 ATP_Q_APPEND(atp_need_rel, rcbp, rc_tlist);
585 }
586 rcbp->rc_state = RCB_RESPONSE_FULL;
587 } else
588 atp_rcb_free(rcbp);
589 } /* atp_send_replies */
590
591
592 static int
593 atp_pack_bdsp(trp, bdsp)
594 register struct atp_trans *trp;
595 register struct atpBDS *bdsp;
596 {
597 register gbuf_t *m = NULL;
598 register int i, datsize = 0;
599 struct atpBDS *bdsbase = bdsp;
600 int error = 0;
601
602 dPrintf(D_M_ATP, D_L_INFO, ("atp_pack_bdsp: socket=%d\n",
603 trp->tr_queue->atp_socket_no));
604
605 for (i = 0; i < ATP_TRESP_MAX; i++, bdsp++) {
606 unsigned short bufsize = UAS_VALUE(bdsp->bdsBuffSz);
607 long bufaddr = UAL_VALUE(bdsp->bdsBuffAddr);
608
609 if ((m = trp->tr_rcv[i]) == NULL)
610 break;
611
612 /* discard ddp hdr on first packet */
613 if (i == 0)
614 gbuf_rinc(m,DDP_X_HDR_SIZE);
615
616 /* this field may contain control information even when
617 no data is present */
618 UAL_UAL(bdsp->bdsUserData,
619 (((at_atp_t *)(gbuf_rptr(m)))->user_bytes));
620 gbuf_rinc(m, ATP_HDR_SIZE);
621
622 if ((bufsize != 0) && (bufaddr != 0)) {
623 /* user expects data back */
624 short tmp = 0;
625 register char *buf = (char *)bufaddr;
626
627 while (m) {
628 unsigned short len = (unsigned short)(gbuf_len(m));
629 if (len) {
630 if (len > bufsize)
631 len = bufsize;
632 if ((error = copyout((caddr_t)gbuf_rptr(m),
633 CAST_USER_ADDR_T(&buf[tmp]),
634 len)) != 0) {
635 return error;
636 }
637 bufsize -= len;
638 tmp += len;
639 }
640 m = gbuf_cont(m);
641 }
642
643 UAS_ASSIGN(bdsp->bdsDataSz, tmp);
644 datsize += (int)tmp;
645 }
646 gbuf_freem(trp->tr_rcv[i]);
647 trp->tr_rcv[i] = NULL;
648 }
649
650 /* report the number of packets */
651 UAS_ASSIGN(((struct atpBDS *)bdsbase)->bdsBuffSz, i);
652
653 dPrintf(D_M_ATP, D_L_INFO, (" : size=%d\n",
654 datsize));
655
656 return 0;
657 } /* atp_pack_bdsp */
658
659
660 /* create an mbuf chain with mbuf packet headers for each ATP response packet
661 * to be sent. m contains the DDP hdr, ATP hdr, and and array of atpBDS structs.
662 * chained to m is an mbuf that contians the actual data pointed to by the atpBDS
663 * structs.
664 */
665 static int
666 atp_unpack_bdsp(atp, m, rcbp, cnt, wait)
667 struct atp_state *atp;
668 gbuf_t *m; /* ddp, atp and bdsp gbuf_t */
669 register struct atp_rcb *rcbp;
670 register int cnt, wait;
671 {
672 register struct atpBDS *bdsp;
673 register gbuf_t *m2, *m1, *m0, *mhdr;
674 caddr_t lastPage;
675 at_atp_t *athp;
676 int i, len;
677 at_socket src_socket;
678
679 struct ddp_atp {
680 char ddp_atp_hdr[TOTAL_ATP_HDR_SIZE];
681 };
682 gbuf_t *mprev, *mlist = 0;
683 gbuf_t *rc_xmt[ATP_TRESP_MAX];
684 unsigned char *m0_rptr, *m0_wptr;
685 int err, offset, space;
686 struct timeval timenow;
687
688 /*
689 * get the user data structure pointer
690 */
691 bdsp = (struct atpBDS *)(AT_ATP_HDR(m)->data);
692
693 /*
694 * Guard against bogus count argument.
695 */
696 if ((unsigned) cnt > ATP_TRESP_MAX) {
697 dPrintf(D_M_ATP, D_L_ERROR,
698 ("atp_unpack_bdsp: bad bds count 0x%x\n", cnt));
699 gbuf_freem(m);
700 return(EINVAL);
701 }
702 if ((src_socket = (at_socket)atp->atp_socket_no) == 0xFF) {
703 /* comparison was to -1, however src_socket is a u_char */
704 gbuf_freem(m);
705 return EPIPE;
706 }
707
708 m0 = gbuf_cont(m);
709 rcbp->rc_xmt = m;
710 rcbp->rc_pktcnt = cnt;
711 rcbp->rc_state = RCB_SENDING;
712 rcbp->rc_not_sent_bitmap = 0;
713
714 if (cnt <= 1) {
715 /*
716 * special case this to
717 * improve AFP write transactions to the server
718 */
719 rcbp->rc_pktcnt = 1;
720 if ((m2 = gbuf_alloc_wait(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE,
721 wait)) == NULL)
722 return 0;
723 gbuf_rinc(m2,AT_WR_OFFSET);
724 gbuf_wset(m2,TOTAL_ATP_HDR_SIZE);
725 *(struct ddp_atp *)(gbuf_rptr(m2))= *(struct ddp_atp *)(gbuf_rptr(m));
726 athp = AT_ATP_HDR(m2);
727 ATP_CLEAR_CONTROL(athp);
728 athp->cmd = ATP_CMD_TRESP;
729 athp->bitmap = 0;
730 athp->eom = 1; /* there's only 1 fragment */
731
732 /* *** why only if cnt > 0? *** */
733 if (cnt > 0)
734 UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
735 if (m0)
736 if (!append_copy((struct mbuf *)m2,
737 (struct mbuf *)m0, wait)) {
738 gbuf_freeb(m2);
739 return 0;
740 }
741 /*
742 * send the message and mark it as sent
743 */
744 AT_DDP_HDR(m2)->src_socket = src_socket;
745 dPrintf(D_M_ATP_LOW, D_L_INFO,
746 ("atp_unpack_bdsp %d, socket=%d, size=%d, cnt=%d\n",
747 0,atp->atp_socket_no,gbuf_msgsize(gbuf_cont(m2)),cnt));
748 mlist = m2;
749 goto l_send;
750 }
751
752 /* create an array of mbuf packet headers for the packets to be sent
753 * to contain the atp and ddp headers with room at the front for the
754 * datalink header.
755 */
756 for (i = 0; i < cnt; i++) {
757 /* all hdrs, packet data and dst addr storage */
758 if ((rc_xmt[i] =
759 gbuf_alloc_wait(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE, wait)) == NULL) {
760 for (cnt = 0; cnt < i; cnt++)
761 if (rc_xmt[cnt])
762 gbuf_freeb(rc_xmt[cnt]);
763 return 0;
764 }
765 }
766
767 /* run through the atpBDS structs and create an mbuf for the data
768 * portion of each packet to be sent. these get chained to the mbufs
769 * containing the ATP and DDP headers. this code assumes that no ATP
770 * packet is contained in more than 2 mbufs (e.i crosses mbuf boundary
771 * no more than one time).
772 */
773 offset = 0;
774 if (m0)
775 space = gbuf_msgsize(m0);
776 for (i = 0; i < cnt; i++) { /* for each hdr mbuf */
777 mhdr = rc_xmt[i];
778 /* setup header fields */
779 gbuf_rinc(mhdr,AT_WR_OFFSET);
780 gbuf_wset(mhdr,TOTAL_ATP_HDR_SIZE);
781 *(struct ddp_atp *)(gbuf_rptr(mhdr))= *(struct ddp_atp *)(gbuf_rptr(m));
782 athp = AT_ATP_HDR(mhdr);
783 ATP_CLEAR_CONTROL(athp);
784 athp->cmd = ATP_CMD_TRESP;
785 athp->bitmap = i;
786 if (i == (cnt - 1))
787 athp->eom = 1; /* for the last fragment */
788 UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
789
790 if ((len = UAS_VALUE(bdsp->bdsBuffSz)) != 0 && m0 != 0 && space > 0) {
791 if ((m1 = m_copym(m0, offset, len, wait)) == 0) {
792 for (i = 0; i < cnt; i++)
793 if (rc_xmt[i])
794 gbuf_freem(rc_xmt[i]);
795 return 0;
796 }
797 gbuf_cont(mhdr) = m1;
798 space -= len;
799 offset += len;
800 }
801
802 AT_DDP_HDR(mhdr)->src_socket = src_socket;
803 dPrintf(D_M_ATP_LOW,D_L_INFO,
804 ("atp_unpack_bdsp %d, socket=%d, size=%d, cnt=%d\n",
805 i,atp->atp_socket_no,gbuf_msgsize(gbuf_cont(mhdr)),cnt));
806 if (mlist)
807 gbuf_next(mprev) = mhdr;
808 else
809 mlist = mhdr;
810 mprev = mhdr;
811 /*
812 * on to the next frag
813 */
814 bdsp++;
815 }
816 /*
817 * send the message
818 */
819 l_send:
820 if (rcbp->rc_xo) {
821 getmicrouptime(&timenow);
822 if (rcbp->rc_timestamp == 0) {
823 if ((rcbp->rc_timestamp = timenow.tv_sec) == 0)
824 rcbp->rc_timestamp = 1;
825 ATP_Q_APPEND(atp_need_rel, rcbp, rc_tlist);
826 }
827 }
828
829 DDP_OUTPUT(mlist);
830 return 0;
831
832 } /* atp_unpack_bdsp */
833
834 #define ATP_SOCKET_LAST (DDP_SOCKET_LAST-6)
835 #define ATP_SOCKET_FIRST (DDP_SOCKET_1st_DYNAMIC)
836 static unsigned int sNext = 0;
837
838 int atp_bind(gref, sVal, flag)
839 gref_t *gref;
840 unsigned int sVal;
841 unsigned char *flag;
842 {
843 extern unsigned char asp_inpC[];
844 extern asp_scb_t *asp_scbQ[];
845 unsigned char inpC, sNextUsed = 0;
846 unsigned int sMin, sMax, sSav;
847 struct atp_state *atp;
848
849 atp = (struct atp_state *)gref->info;
850 if (atp->dflag)
851 atp = (struct atp_state *)atp->atp_msgq;
852
853 sMax = ATP_SOCKET_LAST;
854 sMin = ATP_SOCKET_FIRST;
855 if (flag && (*flag == 3)) {
856 sMin += 40;
857 if (sMin < sNext) {
858 sMin = sNext;
859 sNextUsed = 1;
860 }
861 }
862
863 if ( (sVal != 0) &&
864 ((sVal > sMax) || (sVal < 2) || (sVal == 6) ||
865 (ddp_socket_inuse(sVal, DDP_ATP) &&
866 (atp_inputQ[sVal] != (gref_t *)1)))) {
867 return 0;
868 }
869
870 if (sVal == 0) {
871 inpC = 255;
872 again:
873 for (sVal=sMin; sVal <= sMax; sVal++) {
874 if (!ddp_socket_inuse(sVal, DDP_ATP) ||
875 atp_inputQ[sVal] == (gref_t *)1)
876 break;
877 else if (flag && (*flag == 3) && asp_scbQ[sVal]) {
878 if ((asp_scbQ[sVal]->dflag == *flag)
879 && (asp_inpC[sVal] < inpC) ) {
880 inpC = asp_inpC[sVal];
881 sSav = sVal;
882 }
883 }
884 }
885 if (sVal > sMax) {
886 if (flag && (*flag == 3)) {
887 if (sNextUsed) {
888 sNextUsed = 0;
889 sMax = sNext - 1;
890 sMin = ATP_SOCKET_FIRST+40;
891 goto again;
892 }
893 sNext = 0;
894 *flag = (unsigned char)sSav;
895 }
896 return 0;
897 }
898 }
899 atp->atp_socket_no = (short)sVal;
900 atp_inputQ[sVal] = gref;
901 if (flag == 0)
902 atp_pidM[sVal] = atp->atp_pid;
903 else if (*flag == 3) {
904 sNext = sVal + 1;
905 if (sNext > ATP_SOCKET_LAST)
906 sNext = 0;
907 }
908
909 return (int)sVal;
910 }
911
912 void atp_req_ind(atp, mioc)
913 register struct atp_state *atp;
914 register gbuf_t *mioc;
915 {
916 register struct atp_rcb *rcbp;
917
918 if ((rcbp = atp->atp_attached.head) != 0) {
919 gbuf_cont(mioc) = rcbp->rc_ioctl;
920 rcbp->rc_ioctl = NULL;
921 if (rcbp->rc_xo) {
922 ATP_Q_REMOVE(atp->atp_attached, rcbp, rc_list);
923 rcbp->rc_state = RCB_NOTIFIED;
924 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
925 } else
926 atp_rcb_free(rcbp);
927 if (gbuf_cont(mioc))
928 ((ioc_t *)gbuf_rptr(mioc))->ioc_count = gbuf_msgsize(gbuf_cont(mioc));
929 else
930 ((ioc_t *)gbuf_rptr(mioc))->ioc_count = 0;
931 asp_ack_reply(atp->atp_gref, mioc);
932 } else
933 gbuf_freeb(mioc);
934 }
935
936 void atp_rsp_ind(trp, mioc)
937 register struct atp_trans *trp;
938 register gbuf_t *mioc;
939 {
940 register struct atp_state *atp = trp->tr_queue;
941 register int err;
942 gbuf_t *xm = 0;
943
944 err = 0;
945 {
946 switch (trp->tr_state) {
947 case TRANS_DONE:
948 if (asp_pack_bdsp(trp, &xm) < 0)
949 err = EFAULT;
950 gbuf_cont(mioc) = trp->tr_xmt;
951 trp->tr_xmt = NULL;
952 break;
953
954 case TRANS_FAILED:
955 err = ETIMEDOUT;
956 break;
957
958 default:
959 err = ENOENT;
960 break;
961 }
962 atp_free(trp);
963
964 if (err) {
965 dPrintf(D_M_ATP, D_L_ERROR,
966 ("atp_rsp_ind: TRANSACTION error\n"));
967 atp_iocnak(atp, mioc, err);
968 } else {
969 gbuf_cont(gbuf_cont(mioc)) = xm;
970 atp_iocack(atp, mioc);
971 }
972 }
973 }
974
975 void atp_cancel_req(gref, tid)
976 gref_t *gref;
977 unsigned short tid;
978 {
979 struct atp_state *atp;
980 struct atp_trans *trp;
981
982 atp = (struct atp_state *)gref->info;
983 if (atp->dflag)
984 atp = (struct atp_state *)atp->atp_msgq;
985
986 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
987 if (trp->tr_tid == tid)
988 break;
989 }
990 if (trp != NULL)
991 atp_free(trp);
992 }
993
994 /*
995 * remove atp from the use list
996 */
997 void
998 atp_dequeue_atp(atp)
999 struct atp_state *atp;
1000 {
1001
1002 if (atp == atp_used_list) {
1003 if ((atp_used_list = atp->atp_trans_waiting) != 0)
1004 atp->atp_trans_waiting->atp_rcb_waiting = 0;
1005 } else if (atp->atp_rcb_waiting) {
1006 if ((atp->atp_rcb_waiting->atp_trans_waiting
1007 = atp->atp_trans_waiting) != 0)
1008 atp->atp_trans_waiting->atp_rcb_waiting = atp->atp_rcb_waiting;
1009 }
1010
1011 atp->atp_trans_waiting = 0;
1012 atp->atp_rcb_waiting = 0;
1013 }
1014
1015 void
1016 atp_timout(func, trp, ticks)
1017 void (*func)();
1018 struct atp_trans *trp;
1019 int ticks;
1020 {
1021 unsigned int sum;
1022 struct atp_trans *curr_trp, *prev_trp;
1023
1024 if (trp->tr_tmo_func)
1025 return;
1026
1027 trp->tr_tmo_func = func;
1028 trp->tr_tmo_delta = 1+(ticks>>5);
1029
1030 if (trp_tmo_list == 0) {
1031 trp->tr_tmo_next = trp->tr_tmo_prev = 0;
1032 trp_tmo_list = trp;
1033 return;
1034 }
1035
1036 prev_trp = 0;
1037 curr_trp = trp_tmo_list;
1038 sum = 0;
1039
1040 while (1) {
1041 sum += curr_trp->tr_tmo_delta;
1042 if (sum > trp->tr_tmo_delta) {
1043 sum -= curr_trp->tr_tmo_delta;
1044 trp->tr_tmo_delta -= sum;
1045 curr_trp->tr_tmo_delta -= trp->tr_tmo_delta;
1046 break;
1047 }
1048 prev_trp = curr_trp;
1049 if ((curr_trp = curr_trp->tr_tmo_next) == 0) {
1050 trp->tr_tmo_delta -= sum;
1051 break;
1052 }
1053 }
1054
1055 if (prev_trp) {
1056 trp->tr_tmo_prev = prev_trp;
1057 if ((trp->tr_tmo_next = prev_trp->tr_tmo_next) != 0)
1058 prev_trp->tr_tmo_next->tr_tmo_prev = trp;
1059 prev_trp->tr_tmo_next = trp;
1060 } else {
1061 trp->tr_tmo_prev = 0;
1062 trp->tr_tmo_next = trp_tmo_list;
1063 trp_tmo_list->tr_tmo_prev = trp;
1064 trp_tmo_list = trp;
1065 }
1066 }
1067
1068 void
1069 atp_untimout(func, trp)
1070 void (*func)();
1071 struct atp_trans *trp;
1072 {
1073
1074 if (trp->tr_tmo_func == 0)
1075 return;
1076
1077 if (trp_tmo_list == trp) {
1078 if ((trp_tmo_list = trp->tr_tmo_next) != 0) {
1079 trp_tmo_list->tr_tmo_prev = 0;
1080 trp->tr_tmo_next->tr_tmo_delta += trp->tr_tmo_delta;
1081 }
1082 } else {
1083 if ((trp->tr_tmo_prev->tr_tmo_next = trp->tr_tmo_next) != 0) {
1084 trp->tr_tmo_next->tr_tmo_prev = trp->tr_tmo_prev;
1085 trp->tr_tmo_next->tr_tmo_delta += trp->tr_tmo_delta;
1086 }
1087 }
1088 trp->tr_tmo_func = 0;
1089 }
1090
1091 void
1092 atp_trp_clock_locked(arg)
1093 void *arg;
1094 {
1095 atalk_lock();
1096 atp_trp_clock(arg);
1097 atalk_unlock();
1098 }
1099
1100 void
1101 atp_trp_clock(arg)
1102 void *arg;
1103 {
1104 struct atp_trans *trp;
1105 void (*tr_tmo_func)();
1106
1107 if (trp_tmo_list)
1108 trp_tmo_list->tr_tmo_delta--;
1109 while (((trp = trp_tmo_list) != 0) && (trp_tmo_list->tr_tmo_delta == 0)) {
1110 if ((trp_tmo_list = trp->tr_tmo_next) != 0)
1111 trp_tmo_list->tr_tmo_prev = 0;
1112 if ((tr_tmo_func = trp->tr_tmo_func) != 0) {
1113 trp->tr_tmo_func = 0;
1114 (*tr_tmo_func)(trp);
1115 }
1116 }
1117
1118 timeout(atp_trp_clock_locked, (void *)arg, (1<<5));
1119 }
1120
1121 void
1122 atp_send_req(gref, mioc)
1123 gref_t *gref;
1124 gbuf_t *mioc;
1125 {
1126 register struct atp_state *atp;
1127 register struct atp_trans *trp;
1128 register ioc_t *iocbp;
1129 register at_atp_t *athp;
1130 register at_ddp_t *ddp;
1131 gbuf_t *m, *m2, *bds;
1132 struct atp_set_default *sdb;
1133 int old;
1134 unsigned int timer;
1135 u_short temp_net;
1136
1137 atp = (struct atp_state *)((struct atp_state *)gref->info)->atp_msgq;
1138 iocbp = (ioc_t *)gbuf_rptr(mioc);
1139
1140 if ((trp = atp_trans_alloc(atp)) == NULL) {
1141 l_retry:
1142 ((asp_scb_t *)gref->info)->stat_msg = mioc;
1143 iocbp->ioc_private = (void *)gref;
1144 timeout(atp_retry_req, mioc, 10);
1145 return;
1146 }
1147
1148 m2 = gbuf_cont(mioc);
1149 if ((bds = gbuf_dupb(m2)) == NULL) {
1150 atp_trans_free(trp);
1151 goto l_retry;
1152 }
1153 gbuf_rinc(m2,atpBDSsize);
1154 gbuf_wset(bds,atpBDSsize);
1155 iocbp->ioc_count -= atpBDSsize;
1156 gbuf_cont(m2) = NULL;
1157
1158 old = iocbp->ioc_cmd;
1159 iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST;
1160 sdb = (struct atp_set_default *)gbuf_rptr(m2);
1161
1162 /*
1163 * The at_snd_req library routine multiplies seconds by 100.
1164 * We need to divide by 100 in order to obtain the timer.
1165 */
1166 if ((timer = (sdb->def_rate * HZ)/100) == 0)
1167 timer = HZ;
1168 iocbp->ioc_count -= sizeof(struct atp_set_default);
1169 gbuf_rinc(m2,sizeof(struct atp_set_default));
1170
1171 trp->tr_retry = sdb->def_retries;
1172 trp->tr_timeout = timer;
1173 trp->tr_bdsp = bds;
1174 trp->tr_tid = atp_tid(atp);
1175 trp->tr_xmt = mioc;
1176
1177 /*
1178 * Now fill in the header (and remember the bits
1179 * we need to know)
1180 */
1181 athp = AT_ATP_HDR(m2);
1182 athp->cmd = ATP_CMD_TREQ;
1183 UAS_ASSIGN_HTON(athp->tid, trp->tr_tid);
1184 athp->eom = 0;
1185 athp->sts = 0;
1186 trp->tr_xo = athp->xo;
1187 trp->tr_bitmap = athp->bitmap;
1188 ddp = AT_DDP_HDR(m2);
1189 ddp->type = DDP_ATP;
1190 ddp->src_socket = (at_socket)atp->atp_socket_no;
1191 trp->tr_socket.socket = ddp->dst_socket;
1192 trp->tr_socket.node = ddp->dst_node;
1193 trp->tr_socket.net = NET_VALUE(ddp->dst_net);
1194 trp->tr_local_socket = atp->atp_socket_no;
1195 trp->tr_local_node = ddp->src_node;
1196 temp_net = NET_VALUE(ddp->src_net);
1197 NET_ASSIGN_NOSWAP(trp->tr_local_net, temp_net);
1198
1199 #ifdef NOT_YET
1200 /* save the local information in the gref */
1201 atp->atp_gref->laddr.s_net = NET_VALUE(ddp->src_net);
1202 atp->atp_gref->laddr.s_node = ddp->src_node;
1203 atp->atp_gref->lport = ddp->src_node;
1204 atp->atp_gref->ddptype = DDP_ATP;
1205 #endif
1206
1207 /*
1208 * Put us in the transaction waiting queue
1209 */
1210 ATP_Q_APPEND(atp->atp_trans_wait, trp, tr_list);
1211
1212 /*
1213 * Send the message and set the timer
1214 */
1215 m = (gbuf_t *)copy_pkt(m2, sizeof(llc_header_t));
1216 if (!trp->tr_retry && !trp->tr_bitmap && !trp->tr_xo)
1217 atp_x_done(trp); /* no reason to tie up resources */
1218 else
1219 atp_timout(atp_req_timeout, trp, trp->tr_timeout);
1220 if (m) {
1221 trace_mbufs(D_M_ATP_LOW, " s", m);
1222 DDP_OUTPUT(m);
1223 }
1224 } /* atp_send_req */
1225
1226 void atp_retry_req(arg)
1227 void *arg;
1228 {
1229 gbuf_t *m = (gbuf_t *)arg;
1230 gref_t *gref;
1231
1232 atalk_lock();
1233
1234 gref = (gref_t *)((ioc_t *)gbuf_rptr(m))->ioc_private;
1235 if (gref->info) {
1236 ((asp_scb_t *)gref->info)->stat_msg = 0;
1237 atp_send_req(gref, m);
1238 }
1239 atalk_unlock();
1240 }
1241
1242 void atp_send_rsp(gref, m, wait)
1243 gref_t *gref;
1244 gbuf_t *m;
1245 int wait;
1246 {
1247 register struct atp_state *atp;
1248 register struct atp_rcb *rcbp;
1249 register at_atp_t *athp;
1250 register at_ddp_t *ddp;
1251 int s, xcnt;
1252 u_short temp_net;
1253
1254 atp = (struct atp_state *)gref->info;
1255 if (atp->dflag)
1256 atp = (struct atp_state *)atp->atp_msgq;
1257 ddp = AT_DDP_HDR(m);
1258 athp = AT_ATP_HDR(m);
1259
1260 /*
1261 * search for the corresponding rcb
1262 */
1263 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
1264 if ( (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid)) &&
1265 (rcbp->rc_socket.node == ddp->dst_node) &&
1266 (rcbp->rc_socket.net == NET_VALUE(ddp->dst_net)) &&
1267 (rcbp->rc_socket.socket == ddp->dst_socket) )
1268 break;
1269 }
1270
1271 /*
1272 * If it has already been sent then drop the request
1273 */
1274 if ((rcbp && (rcbp->rc_state != RCB_NOTIFIED)) ||
1275 (rcbp == NULL && athp->xo) ) {
1276 gbuf_freem(m);
1277 return;
1278 }
1279
1280 if (rcbp == NULL) { /* a response is being sent for an ALO transaction */
1281 if ((rcbp = atp_rcb_alloc(atp)) == NULL) {
1282 gbuf_freem(m);
1283 return;
1284 }
1285 rcbp->rc_ioctl = 0;
1286 rcbp->rc_socket.socket = ddp->dst_socket;
1287 rcbp->rc_socket.node = ddp->dst_node;
1288 rcbp->rc_socket.net = NET_VALUE(ddp->dst_net);
1289 rcbp->rc_tid = UAS_VALUE_NTOH(athp->tid);
1290 rcbp->rc_bitmap = 0xff;
1291 rcbp->rc_xo = 0;
1292 rcbp->rc_state = RCB_RESPONSE_FULL;
1293 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
1294 }
1295 else if (ddp->src_node == 0) {
1296 temp_net = NET_VALUE_NOSWAP(rcbp->rc_local_net);
1297 NET_ASSIGN(ddp->src_net, temp_net);
1298 ddp->src_node = rcbp->rc_local_node;
1299 }
1300
1301 xcnt = get_bds_entries(m);
1302 s = atp_unpack_bdsp(atp, m, rcbp, xcnt, wait);
1303 if (s == 0)
1304 atp_send_replies(atp, rcbp);
1305 } /* atp_send_rsp */
1306
1307 int asp_pack_bdsp(trp, xm)
1308 register struct atp_trans *trp;
1309 gbuf_t **xm;
1310 {
1311 register struct atpBDS *bdsp;
1312 register gbuf_t *m, *m2;
1313 register int i;
1314 gbuf_t *m_prev, *m_head = 0;
1315
1316 dPrintf(D_M_ATP, D_L_INFO, ("asp_pack_bdsp: socket=%d\n",
1317 trp->tr_queue->atp_socket_no));
1318
1319 if ((m2 = trp->tr_bdsp) == NULL)
1320 return 0;
1321 trp->tr_bdsp = NULL;
1322 bdsp = (struct atpBDS *)gbuf_rptr(m2);
1323
1324 for (i = 0; (i < ATP_TRESP_MAX &&
1325 bdsp < (struct atpBDS *)(gbuf_wptr(m2))); i++) {
1326 if ((m = trp->tr_rcv[i]) == NULL)
1327 break;
1328 if (i == 0) {
1329 /* discard ddp hdr on first packet */
1330 gbuf_rinc(m,DDP_X_HDR_SIZE);
1331 }
1332
1333 UAL_UAL(bdsp->bdsUserData, (((at_atp_t *)(gbuf_rptr(m)))->user_bytes));
1334 gbuf_rinc(m, ATP_HDR_SIZE);
1335
1336 if (UAL_VALUE(bdsp->bdsBuffAddr)) {
1337 short tmp = 0;
1338
1339 /* user expects data back */
1340 m = gbuf_strip(m);
1341 if (m_head == 0)
1342 m_head = m;
1343 else
1344 gbuf_cont(m_prev) = m;
1345 if (m) {
1346 tmp = (short)gbuf_len(m);
1347 while (gbuf_cont(m)) {
1348 m = gbuf_cont(m);
1349 tmp += (short)(gbuf_len(m));
1350 }
1351 m_prev = m;
1352 }
1353 UAS_ASSIGN(bdsp->bdsDataSz, tmp);
1354 }
1355 trp->tr_rcv[i] = NULL;
1356 bdsp++;
1357
1358 }
1359 /*
1360 * report the number of packets
1361 */
1362 UAS_ASSIGN(((struct atpBDS *)gbuf_rptr(m2))->bdsBuffSz, i);
1363
1364 if (trp->tr_xmt) /* an ioctl block is still held? */
1365 gbuf_cont(trp->tr_xmt) = m2;
1366 else
1367 trp->tr_xmt = m2;
1368
1369 if (m_head)
1370 *xm = m_head;
1371 else
1372 *xm = 0;
1373
1374 dPrintf(D_M_ATP, D_L_INFO, (" : size=%d\n",
1375 gbuf_msgsize(*xm)));
1376
1377 return 0;
1378 }
1379
1380 /*
1381 * The following routines are direct entries from system
1382 * calls to allow fast sending and recving of ATP data.
1383 */
1384
1385 int
1386 _ATPsndreq(fd, buf, len, nowait, err, proc)
1387 int fd;
1388 unsigned char *buf;
1389 int len;
1390 int nowait;
1391 int *err;
1392 void *proc;
1393 {
1394 gref_t *gref;
1395 int rc;
1396 unsigned short tid;
1397 unsigned int timer;
1398 register struct atp_state *atp;
1399 register struct atp_trans *trp;
1400 register ioc_t *iocbp;
1401 register at_atp_t *athp;
1402 register at_ddp_t *ddp;
1403 struct atp_set_default *sdb;
1404 gbuf_t *m2, *m, *mioc;
1405 char bds[atpBDSsize];
1406
1407 if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
1408 return -1;
1409
1410 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1411 || (atp->atp_flags & ATP_CLOSING)) {
1412 dPrintf(D_M_ATP, D_L_ERROR, ("ATPsndreq: stale handle=0x%x, pid=%d\n",
1413 (u_int) gref, gref->pid));
1414 file_drop(fd);
1415 *err = EINVAL;
1416 return -1;
1417 }
1418
1419
1420 while ((mioc = gbuf_alloc(sizeof(ioc_t), PRI_MED)) == 0) {
1421 struct timespec ts;
1422 /* the vaue of 10n terms of hz is 100ms */
1423 ts.tv_sec = 0;
1424 ts.tv_nsec = 100 *1000 * NSEC_PER_USEC;
1425
1426 rc = msleep(&atp->atp_delay_event, atalk_mutex, PSOCK | PCATCH, "atpmioc", &ts);
1427 if (rc != 0) {
1428 *err = rc;
1429 file_drop(fd);
1430 return -1;
1431 }
1432
1433 }
1434 gbuf_wset(mioc,sizeof(ioc_t));
1435 len -= atpBDSsize;
1436 while ((m2 = gbuf_alloc(len, PRI_MED)) == 0) {
1437 struct timespec ts;
1438 /* the vaue of 10n terms of hz is 100ms */
1439 ts.tv_sec = 0;
1440 ts.tv_nsec = 100 *1000 * NSEC_PER_USEC;
1441
1442 rc = msleep(&atp->atp_delay_event, atalk_mutex, PSOCK | PCATCH, "atpm2", &ts);
1443 if (rc != 0) {
1444 gbuf_freeb(mioc);
1445 file_drop(fd);
1446 *err = rc;
1447 return -1;
1448 }
1449 }
1450 gbuf_wset(m2, len);
1451 gbuf_cont(mioc) = m2;
1452 if (((*err = copyin(CAST_USER_ADDR_T(buf), (caddr_t)bds, atpBDSsize)) != 0)
1453 || ((*err = copyin(CAST_USER_ADDR_T(&buf[atpBDSsize]),
1454 (caddr_t)gbuf_rptr(m2), len)) != 0)) {
1455 gbuf_freem(mioc);
1456 file_drop(fd);
1457 return -1;
1458 }
1459 gbuf_set_type(mioc, MSG_IOCTL);
1460 iocbp = (ioc_t *)gbuf_rptr(mioc);
1461 iocbp->ioc_count = len;
1462 iocbp->ioc_cmd = nowait ? AT_ATP_ISSUE_REQUEST_NOTE : AT_ATP_ISSUE_REQUEST;
1463 sdb = (struct atp_set_default *)gbuf_rptr(m2);
1464
1465 /*
1466 * The at_snd_req library routine multiplies seconds by 100.
1467 * We need to divide by 100 in order to obtain the timer.
1468 */
1469 if ((timer = (sdb->def_rate * HZ)/100) == 0)
1470 timer = HZ;
1471 iocbp->ioc_count -= sizeof(struct atp_set_default);
1472 gbuf_rinc(m2,sizeof(struct atp_set_default));
1473
1474 /*
1475 * allocate and set up the transaction record
1476 */
1477 while ((trp = atp_trans_alloc(atp)) == 0) {
1478 struct timespec ts;
1479 /* the vaue of 10n terms of hz is 100ms */
1480 ts.tv_sec = 0;
1481 ts.tv_nsec = 100 *1000 * NSEC_PER_USEC;
1482
1483 rc = msleep(&atp->atp_delay_event, atalk_mutex, PSOCK | PCATCH, "atptrp", &ts);
1484 if (rc != 0) {
1485 gbuf_freem(mioc);
1486 file_drop(fd);
1487 *err = rc;
1488 return -1;
1489 }
1490 }
1491 trp->tr_retry = sdb->def_retries;
1492 trp->tr_timeout = timer;
1493 trp->tr_bdsp = NULL;
1494 trp->tr_tid = atp_tid(atp);
1495 tid = trp->tr_tid;
1496
1497 /*
1498 * remember the IOCTL packet so we can ack it
1499 * later
1500 */
1501 trp->tr_xmt = mioc;
1502
1503 /*
1504 * Now fill in the header (and remember the bits
1505 * we need to know)
1506 */
1507 athp = AT_ATP_HDR(m2);
1508 athp->cmd = ATP_CMD_TREQ;
1509 UAS_ASSIGN_HTON(athp->tid, trp->tr_tid);
1510 athp->eom = 0;
1511 athp->sts = 0;
1512 trp->tr_xo = athp->xo;
1513 trp->tr_bitmap = athp->bitmap;
1514 ddp = AT_DDP_HDR(m2);
1515 ddp->type = DDP_ATP;
1516 ddp->src_socket = (at_socket)atp->atp_socket_no;
1517 ddp->src_node = 0;
1518 trp->tr_socket.socket = ddp->dst_socket;
1519 trp->tr_socket.node = ddp->dst_node;
1520 trp->tr_socket.net = NET_VALUE(ddp->dst_net);
1521 trp->tr_local_socket = atp->atp_socket_no;
1522
1523 #ifdef NOT_YET
1524 /* save the local information in the gref */
1525 atp->atp_gref->laddr.s_net = NET_VALUE(ddp->src_net);
1526 atp->atp_gref->laddr.s_node = ddp->src_node;
1527 atp->atp_gref->lport = ddp->src_node;
1528 atp->atp_gref->ddptype = DDP_ATP;
1529 #endif
1530
1531 /*
1532 * Put us in the transaction waiting queue
1533 */
1534 ATP_Q_APPEND(atp->atp_trans_wait, trp, tr_list);
1535
1536 /*
1537 * Send the message and set the timer
1538 */
1539 m = (gbuf_t *)copy_pkt(m2, sizeof(llc_header_t));
1540 if ( !trp->tr_retry && !trp->tr_bitmap && !trp->tr_xo)
1541 atp_x_done(trp); /* no reason to tie up resources */
1542 else
1543 atp_timout(atp_req_timeout, trp, trp->tr_timeout);
1544 if (m)
1545 DDP_OUTPUT(m);
1546
1547 if (nowait) {
1548 file_drop(fd);
1549 return (int)tid;
1550 }
1551
1552 /*
1553 * wait for the transaction to complete
1554 */
1555 while ((trp->tr_state != TRANS_DONE) && (trp->tr_state != TRANS_FAILED) &&
1556 (trp->tr_state != TRANS_ABORTING)) {
1557 trp->tr_rsp_wait = 1;
1558 rc = msleep(&trp->tr_event, atalk_mutex, PSOCK | PCATCH, "atpsndreq", 0);
1559 if (rc != 0) {
1560 trp->tr_rsp_wait = 0;
1561 file_drop(fd);
1562 *err = rc;
1563 return -1;
1564 }
1565 }
1566 trp->tr_rsp_wait = 0;
1567
1568
1569 if (trp->tr_state == TRANS_FAILED || trp->tr_state == TRANS_ABORTING) {
1570 /*
1571 * transaction timed out, return error
1572 */
1573 atp_free(trp);
1574 file_drop(fd);
1575 *err = ETIMEDOUT;
1576 return -1;
1577 }
1578
1579 /*
1580 * copy out the recv data
1581 */
1582 if ((*err = atp_pack_bdsp(trp, (struct atpBDS *)bds)) != 0) {
1583 atp_free(trp);
1584 file_drop(fd);
1585 return -1;
1586 }
1587
1588 /*
1589 * copyout the result info
1590 */
1591 if ((*err = copyout((caddr_t)bds, CAST_USER_ADDR_T(buf), atpBDSsize)) != 0) {
1592 atp_free(trp);
1593 file_drop(fd);
1594 return -1;
1595 }
1596
1597 atp_free(trp);
1598 file_drop(fd);
1599
1600 return (int)tid;
1601 } /* _ATPsndreq */
1602
1603
1604 /* entry point for ATP send response. respbuf contains a DDP hdr,
1605 * ATP hdr, and atpBDS array. The bdsDataSz field of the first atpBDS
1606 * struct contains the number of atpBDS structs in the array. resplen
1607 * contains the len of the data in respbuf and datalen contains the
1608 * len of the data buffer holding the response packets which the atpBDS
1609 * struct entries point to.
1610 */
1611 int
1612 _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
1613 int fd;
1614 unsigned char *respbuff;
1615 int resplen;
1616 int datalen;
1617 int *err;
1618 void *proc;
1619 {
1620 gref_t *gref;
1621 int s, rc;
1622 long bufaddr;
1623 gbuf_t *m, *mdata;
1624 short space;
1625 int size;
1626 struct atp_state *atp;
1627 struct atpBDS *bdsp;
1628 u_int16_t *bufsz;
1629 char *buf;
1630 int bds_cnt, count, len;
1631 caddr_t dataptr;
1632
1633 if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
1634 return -1;
1635
1636 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1637 || (atp->atp_flags & ATP_CLOSING)) {
1638 dPrintf(D_M_ATP, D_L_ERROR, ("ATPsndrsp: stale handle=0x%x, pid=%d\n",
1639 (u_int) gref, gref->pid));
1640
1641 file_drop(fd);
1642 *err = EINVAL;
1643 return -1;
1644 }
1645
1646 /*
1647 * allocate buffer and copy in the response info
1648 */
1649 if ((m = gbuf_alloc_wait(resplen, TRUE)) == 0) {
1650 *err = ENOMEM;
1651 file_drop(fd);
1652 return -1;
1653 }
1654 if ((*err = copyin(CAST_USER_ADDR_T(respbuff), (caddr_t)gbuf_rptr(m), resplen)) != 0) {
1655 gbuf_freeb(m);
1656 file_drop(fd);
1657 return -1;
1658 }
1659 gbuf_wset(m,resplen);
1660 ((at_ddp_t *)gbuf_rptr(m))->src_node = 0;
1661 bdsp = (struct atpBDS *)(gbuf_rptr(m) + TOTAL_ATP_HDR_SIZE);
1662
1663 /*
1664 * allocate buffers and copy in the response data.
1665 * note that only the size field of the atpBDS field
1666 * is used internally in the kernel.
1667 */
1668 bds_cnt = get_bds_entries(m); /* count of # entries */
1669 /* check correctness of parameters */
1670 if (bds_cnt > ATP_TRESP_MAX) {
1671 gbuf_freem(m);
1672 *err = EINVAL;
1673 file_drop(fd);
1674 return -1;
1675 }
1676
1677 for (size = 0, count = 0; count < bds_cnt; count++) {
1678 size += UAS_VALUE(bdsp[count].bdsBuffSz);
1679 }
1680 if (size > datalen) {
1681 gbuf_freem(m);
1682 *err = EINVAL;
1683 file_drop(fd);
1684 return -1;
1685 }
1686
1687 /* get the first mbuf */
1688 if ((mdata = gbuf_alloc_wait((space = (size > MCLBYTES ? MCLBYTES : size)), TRUE)) == 0) {
1689 gbuf_freem(m);
1690 file_drop(fd);
1691 *err = ENOMEM;
1692 return -1;
1693 }
1694 gbuf_cont(m) = mdata;
1695 dataptr = mtod(mdata, caddr_t);
1696 for (count = 0; count < bds_cnt; bdsp++, count++) {
1697 if ((bufaddr = UAL_VALUE(bdsp->bdsBuffAddr)) != 0 &&
1698 (len = UAS_VALUE(bdsp->bdsBuffSz)) != 0) {
1699 if (len > space) { /* enough room ? */
1700 gbuf_wset(mdata, dataptr - mtod(mdata, caddr_t)); /* set len of last mbuf */
1701 /* allocate the next mbuf */
1702 if ((gbuf_cont(mdata) = m_get((M_WAIT), MSG_DATA)) == 0) {
1703 gbuf_freem(m);
1704 file_drop(fd);
1705 *err = ENOMEM;
1706 return -1;
1707 }
1708 mdata = gbuf_cont(mdata);
1709 MCLGET(mdata, M_WAIT);
1710 if (!(mdata->m_flags & M_EXT)) {
1711 m_freem(m);
1712 file_drop(fd);
1713 return(NULL);
1714 }
1715 dataptr = mtod(mdata, caddr_t);
1716 space = MCLBYTES;
1717 }
1718 /* do the copyin */
1719 if ((*err = copyin(CAST_USER_ADDR_T(bufaddr), dataptr, len)) != 0) {
1720 gbuf_freem(m);
1721 file_drop(fd);
1722 return -1;
1723 }
1724 dataptr += len;
1725 space -= len;
1726 }
1727 }
1728 gbuf_wset(mdata, dataptr - mtod(mdata, caddr_t)); /* set len of last mbuf */
1729 gbuf_cont(m)->m_pkthdr.len = size; /* set packet hdr len */
1730
1731 atp_send_rsp(gref, m, TRUE);
1732 file_drop(fd);
1733 return 0;
1734 }
1735
1736 int
1737 _ATPgetreq(fd, buf, buflen, err, proc)
1738 int fd;
1739 unsigned char *buf;
1740 int buflen;
1741 int *err;
1742 void *proc;
1743 {
1744 gref_t *gref;
1745 register struct atp_state *atp;
1746 register struct atp_rcb *rcbp;
1747 register gbuf_t *m, *m_head;
1748 int size, len;
1749
1750 if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
1751 return -1;
1752
1753 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1754 || (atp->atp_flags & ATP_CLOSING)) {
1755 dPrintf(D_M_ATP, D_L_ERROR, ("ATPgetreq: stale handle=0x%x, pid=%d\n",
1756 (u_int) gref, gref->pid));
1757 file_drop(fd);
1758 *err = EINVAL;
1759 return -1;
1760 }
1761
1762 if ((rcbp = atp->atp_attached.head) != NULL) {
1763 /*
1764 * Got one, move it to the active response Q
1765 */
1766 m_head = rcbp->rc_ioctl;
1767 rcbp->rc_ioctl = NULL;
1768
1769 if (rcbp->rc_xo) {
1770 ATP_Q_REMOVE(atp->atp_attached, rcbp, rc_list);
1771 rcbp->rc_state = RCB_NOTIFIED;
1772 ATP_Q_APPEND(atp->atp_rcb, rcbp, rc_list);
1773 } else {
1774 /* detach rcbp from attached queue,
1775 * and free any outstanding resources
1776 */
1777 atp_rcb_free(rcbp);
1778 }
1779
1780 /*
1781 * copyout the request data, including the protocol header
1782 */
1783 for (size=0, m=m_head; m; m = gbuf_cont(m)) {
1784 if ((len = gbuf_len(m)) > buflen)
1785 len = buflen;
1786 copyout((caddr_t)gbuf_rptr(m), CAST_USER_ADDR_T(&buf[size]), len);
1787 size += len;
1788 if ((buflen -= len) == 0)
1789 break;
1790 }
1791 gbuf_freem(m_head);
1792
1793 file_drop(fd);
1794 return size;
1795 }
1796
1797 file_drop(fd);
1798 return -1;
1799 }
1800
1801 int
1802 _ATPgetrsp(fd, bdsp, err, proc)
1803 int fd;
1804 struct atpBDS *bdsp;
1805 int *err;
1806 void *proc;
1807 {
1808 gref_t *gref;
1809 register struct atp_state *atp;
1810 register struct atp_trans *trp;
1811 int tid;
1812 char bds[atpBDSsize];
1813
1814 if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
1815 return -1;
1816
1817 if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
1818 || (atp->atp_flags & ATP_CLOSING)) {
1819 dPrintf(D_M_ATP, D_L_ERROR, ("ATPgetrsp: stale handle=0x%x, pid=%d\n",
1820 (u_int) gref, gref->pid));
1821 file_drop(fd);
1822 *err = EINVAL;
1823 return -1;
1824 }
1825
1826 for (trp = atp->atp_trans_wait.head; trp; trp = trp->tr_list.next) {
1827 dPrintf(D_M_ATP, D_L_INFO,
1828 ("ATPgetrsp: atp:0x%x, trp:0x%x, state:%d\n",
1829 (u_int) atp, (u_int) trp, trp->tr_state));
1830
1831 switch (trp->tr_state) {
1832 case TRANS_DONE:
1833 if ((*err = copyin(CAST_USER_ADDR_T(bdsp),
1834 (caddr_t)bds, sizeof(bds))) != 0) {
1835 atp_free(trp);
1836 file_drop(fd);
1837 return -1;
1838 }
1839 if ((*err = atp_pack_bdsp(trp, (struct atpBDS *)bds)) != 0) {
1840 atp_free(trp);
1841 file_drop(fd);
1842 return -1;
1843 }
1844 tid = (int)trp->tr_tid;
1845 atp_free(trp);
1846 if ((*err = copyout((caddr_t)bds, CAST_USER_ADDR_T(bdsp), sizeof(bds))) != 0) {
1847 file_drop(fd);
1848 return -1;
1849 }
1850 file_drop(fd);
1851 return tid;
1852
1853 case TRANS_FAILED:
1854 /*
1855 * transaction timed out, return error
1856 */
1857 atp_free(trp);
1858 file_drop(fd);
1859 *err = ETIMEDOUT;
1860 return -1;
1861
1862 default:
1863 continue;
1864 }
1865 }
1866
1867 file_drop(fd);
1868 *err = EINVAL;
1869 return -1;
1870 }
1871
1872 void
1873 atp_drop_req(gref, m)
1874 gref_t *gref;
1875 gbuf_t *m;
1876 {
1877 struct atp_state *atp;
1878 struct atp_rcb *rcbp;
1879 at_atp_t *athp;
1880 at_ddp_t *ddp;
1881
1882 atp = (struct atp_state *)gref->info;
1883 if (atp->dflag)
1884 atp = (struct atp_state *)atp->atp_msgq;
1885 ddp = AT_DDP_HDR(m);
1886 athp = AT_ATP_HDR(m);
1887
1888 /*
1889 * search for the corresponding rcb
1890 */
1891 for (rcbp = atp->atp_rcb.head; rcbp; rcbp = rcbp->rc_list.next) {
1892 if ( (rcbp->rc_tid == UAS_VALUE_NTOH(athp->tid)) &&
1893 (rcbp->rc_socket.node == ddp->src_node) &&
1894 (rcbp->rc_socket.net == NET_VALUE(ddp->src_net)) &&
1895 (rcbp->rc_socket.socket == ddp->src_socket) )
1896 break;
1897 }
1898
1899 /*
1900 * drop the request
1901 */
1902 if (rcbp)
1903 atp_rcb_free(rcbp);
1904
1905 gbuf_freem(m);
1906 }