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