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