1/*
2 * Copyright (c) 1995-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 *  Change Log:
30 *    Created February 20, 1995 by Tuyen Nguyen
31 *    Modified for MP, 1996 by Tuyen Nguyen
32 *   Modified, March 17, 1997 by Tuyen Nguyen for MacOSX.
33 */
34
35#include <sys/errno.h>
36#include <sys/types.h>
37#include <sys/param.h>
38#include <machine/spl.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/proc.h>
42#include <sys/filedesc.h>
43#include <sys/fcntl.h>
44#include <sys/mbuf.h>
45#include <sys/ioctl.h>
46#include <sys/malloc.h>
47#include <kern/locks.h>
48#include <sys/socket.h>
49#include <sys/socketvar.h>
50
51#include <net/if.h>
52
53#include <netat/sysglue.h>
54#include <netat/appletalk.h>
55#include <netat/at_pcb.h>
56#include <netat/atp.h>
57#include <netat/ddp.h>
58#include <netat/asp.h>
59#include <netat/at_var.h>
60#include <netat/debug.h>
61
62
63#define atpBDSsize    (sizeof(struct atpBDS)*ATP_TRESP_MAX)
64#define aspCMDsize    (atpBDSsize+sizeof(struct atp_set_default)+TOTAL_ATP_HDR_SIZE)
65#define SCBS_PER_BLK  16
66#define TICKS_PER_SEC HZ
67#define SESS_TMO_RES  2
68#define DEF_SESS_TMO  120
69#define NEXT_SEQ_NUM(x) (x = (x == 65535) ? 0 : (x + 1))
70#define MAX_RCV_CNT   5
71#define BAD_REMADDR(addr) \
72	( (*(long *)&scb->rem_addr != *(long *)&addr) \
73	&& ((scb->rem_addr.net != addr.net) \
74		|| (scb->rem_addr.node != addr.node)) )
75
76StaticProc asp_scb_t *asp_find_scb(unsigned char, at_inet_t *);
77StaticProc asp_scb_t *asp_scb_alloc(void);
78
79StaticProc void asp_putnext(gref_t *, gbuf_t *);
80StaticProc void asp_iocack(gref_t *, gbuf_t *);
81StaticProc void asp_iocnak(gref_t *, gbuf_t *, int);
82StaticProc void asp_dequeue_scb(asp_scb_t *);
83StaticProc void asp_scb_free(asp_scb_t *);
84StaticProc void asp_timout(asp_tmo_func,  asp_scb_t *, int);
85StaticProc void asp_untimout(asp_tmo_func,  asp_scb_t *);
86StaticProc void asp_hangup(asp_scb_t *);
87StaticProc void asp_send_tickle(asp_scb_t *);
88StaticProc void asp_send_tickle_locked(void *);
89StaticProc void asp_accept(asp_scb_t *scb, asp_scb_t *sess_scb, gbuf_t *m);
90StaticProc int  asp_send_req(gref_t *, gbuf_t *, at_inet_t *, at_retry_t *, asp_word_t *,
91							unsigned char , unsigned char, unsigned char);
92
93extern at_ifaddr_t *ifID_home;
94extern int atp_pidM[];
95extern gref_t *atp_inputQ[];
96extern lck_mtx_t *atalk_mutex;
97gbuf_t *scb_resource_m = 0;
98unsigned char asp_inpC[256];
99asp_scb_t *asp_scbQ[256];
100
101static at_retry_t asp_def_retry = {2, -1, 1};
102static unsigned char scb_tmo_cnt;
103asp_scb_t *scb_used_list;
104static asp_scb_t *scb_tmo_list;
105asp_scb_t *scb_free_list;
106
107int asp_readable(gref_t *);
108
109int
110asp_readable(gref)
111	gref_t *gref;
112{
113	return (((asp_scb_t *)gref->info)->sess_ioc ? 1 : 0);
114}
115
116void
117asp_init()
118{
119	scb_tmo_cnt = 1;
120	scb_tmo_list = 0;
121	scb_used_list = 0;
122	scb_free_list = 0;
123	bzero(asp_inpC, sizeof(asp_inpC));
124	bzero(asp_scbQ, sizeof(asp_scbQ));
125}
126
127/*
128 * the open routine allocates a state structure
129 */
130int asp_open(gref)
131	gref_t *gref;
132{
133	asp_scb_t *scb;
134
135	/*
136	 * if no asp structure available, return failure
137	 */
138	if ((scb = asp_scb_alloc()) == 0)
139	    return ENOBUFS;
140
141	/*
142	 * initialize the gref data structure
143	 */
144	gref->info = (void *)scb;
145	gref->readable = asp_readable;
146
147	/*
148	 * initialize the scb data structure
149	 */
150	scb->dflag = 1;
151	scb->magic_num = 222;
152	scb->state = ASPSTATE_Idle;
153	scb->pid = gref->pid;
154	scb->gref = gref;
155	scb->session_timer = DEF_SESS_TMO;
156	scb->cmd_retry = asp_def_retry;
157	if ((scb->next_scb = scb_used_list) != 0)
158		scb->next_scb->prev_scb = scb;
159	scb_used_list = scb;
160
161	/*
162	 * return success
163	 */
164	dPrintf(D_M_ASP, D_L_INFO, ("asp_open: pid=%d\n", scb->pid));
165	return 0;
166} /* asp_open */
167
168/*
169 * the close routine frees all the data structures
170 */
171int
172asp_close(gref)
173	gref_t *gref;
174{
175	unsigned char sock_num;
176	asp_scb_t *scb, *new_scb;
177	gbuf_t *m;
178
179	scb = (asp_scb_t *)gref->info;
180	dPrintf(D_M_ASP, D_L_INFO, ("asp_close: loc=%d\n",
181		scb->loc_addr.socket));
182
183	if (scb->pid && scb->sess_ioc && (scb->dflag != 1)) {
184		/*
185		 * send the CloseSess response to peer
186		 */
187		if (gbuf_type(scb->sess_ioc) != MSG_PROTO) {
188			m = scb->sess_ioc;
189			scb->sess_ioc = gbuf_next(m);
190			atp_send_rsp(scb->gref, m, TRUE);
191		}
192	}
193
194	if (scb->atp_state) {
195		sock_num = scb->loc_addr.socket;
196		if ((scb->dflag != 1) && scb->stat_msg) {
197			untimeout(atp_retry_req, scb->stat_msg);
198			gbuf_freem(scb->stat_msg);
199			scb->stat_msg = 0;
200		}
201		if (asp_scbQ[sock_num]->next_scb == 0) {
202			asp_scbQ[sock_num] = 0;
203			asp_inpC[sock_num] = 0;
204			dPrintf(D_M_ASP, D_L_INFO,
205			("         : atp_close(), loc=%d\n", scb->loc_addr.socket));
206			atp_close(gref, 0);
207		} else {
208			asp_inpC[sock_num]--;
209			if (scb == asp_scbQ[sock_num]) {
210				new_scb = scb->next_scb;
211				new_scb->prev_scb = 0;
212				asp_scbQ[sock_num] = new_scb;
213				new_scb->atp_state->atp_gref = new_scb->gref;
214				new_scb->atp_state->pid = new_scb->pid;
215				atp_inputQ[sock_num] = new_scb->gref;
216			} else {
217				if ((scb->prev_scb->next_scb = scb->next_scb) != 0)
218					scb->next_scb->prev_scb = scb->prev_scb;
219			}
220			scb->next_scb = 0;
221		}
222	} else
223		asp_dequeue_scb(scb);
224
225	/*
226	 * free all allocated blocks if any
227	 */
228	if (scb->stat_msg) {
229		gbuf_freem(scb->stat_msg);
230		scb->stat_msg = 0;
231	}
232	if (scb->sess_ioc) {
233		gbuf_freel(scb->sess_ioc);
234		scb->sess_ioc = 0;
235	}
236	if (scb->req_msgq) {
237		gbuf_freel(scb->req_msgq);
238		scb->req_msgq = 0;
239	}
240
241	scb->rem_addr.node = 0;
242
243	/*
244	 * stop all timers
245	 */
246	scb->tmo_cnt = 0;
247	asp_untimout(asp_hangup, scb);
248	untimeout(asp_send_tickle_locked, (void *)scb); /* added for 2225395 */
249
250	/*
251	 * free the asp session control block
252	 */
253	scb->state = ASPSTATE_Close;
254	asp_scb_free(scb);
255	return 0;
256} /* asp_close */
257
258#if DEBUG
259
260static const char *aspStateStr(int);
261
262static const char *aspStateStr(state)
263     int state;
264{
265  return ((state==ASPSTATE_Close)? "Close":
266	  (state==ASPSTATE_Idle)? "Idle":
267	  (state==ASPSTATE_WaitingForGetStatusRsp)? "GetStatusRsp":
268	  (state==ASPSTATE_WaitingForOpenSessRsp)? "OpenSessRsp":
269	  (state==ASPSTATE_WaitingForCommandRsp)? "CmdRsp":
270	  (state==ASPSTATE_WaitingForWriteContinue)? "WriteCont":
271	  (state==ASPSTATE_WaitingForWriteRsp)? "WriteRsp":
272	  (state==ASPSTATE_WaitingForWriteContinueRsp)? "WriteContRsp":
273	  (state==ASPSTATE_WaitingForCloseSessRsp)? "CloseSessRsp":
274	  "unknown");
275}
276
277static const char *aspCmdStr(int);
278
279static const char *aspCmdStr(aspCmd)
280     int aspCmd;
281{
282return ((aspCmd==ASPFUNC_CloseSess)? "CloseSess":
283	(aspCmd==ASPFUNC_Command)? "Command":
284	(aspCmd==ASPFUNC_GetStatus)? "GetStatus":
285	(aspCmd==ASPFUNC_OpenSess)? "OpenSess":
286	(aspCmd==ASPFUNC_Tickle)? "Tickle":
287	(aspCmd==ASPFUNC_Write)? "Write":
288	(aspCmd==ASPFUNC_WriteContinue)? "WriteContinue":
289	(aspCmd==ASPFUNC_Attention)? "Attention":
290	(aspCmd==ASPFUNC_CmdReply)? "CmdReply": "unknown");
291}
292
293static const char *aspIOCStr(int);
294
295static const char *aspIOCStr(aspIOC)
296     int aspIOC;
297{
298return (
299	(aspIOC==ASPIOC_ClientBind)? "ClientBind":
300	(aspIOC==ASPIOC_CloseSession)? "CloseSession":
301	(aspIOC==ASPIOC_GetLocEntity)? "GetLocEntity":
302	(aspIOC==ASPIOC_GetRemEntity)? "GetRemEntity":
303	(aspIOC==ASPIOC_GetSession)? "GetSession":
304	(aspIOC==ASPIOC_GetStatus)? "GetStatus":
305	(aspIOC==ASPIOC_ListenerBind)? "ListenerBind":
306	(aspIOC==ASPIOC_OpenSession)? "OpenSession":
307	(aspIOC==ASPIOC_StatusBlock)? "StatusBlock":
308	(aspIOC==ASPIOC_SetPid)? "SetPid":
309	(aspIOC==ASPIOC_GetSessId)? "GetSessId":
310	(aspIOC==ASPIOC_EnableSelect)? "EnableSelect":
311	(aspIOC==ASPIOC_Look)? "Look":
312	"unknown"
313	);
314}
315#endif /* DEBUG */
316
317#ifdef AT_MBUF_TRACE
318
319static char mbuf_str[100];
320char *mbuf_totals()
321{
322  snprintf(mbuf_str, sizeof(mbuf_str),
323	  /*
324	  "dat = %d, prot = %d, ioc = %d, err = %d, hu = %d, ack = %d, nak = %d, ctl = %d",
325	  */
326	  "dat = %d, prot = %d, ioc = %d, ctl = %d",
327	  mbstat.m_mtypes[MSG_DATA], mbstat.m_mtypes[MSG_PROTO], mbstat.m_mtypes[MSG_IOCTL],
328	  /*
329	  mbstat.m_mtypes[MSG_ERROR], mbstat.m_mtypes[MSG_HANGUP], mbstat.m_mtypes[MSG_IOCACK],
330	  mbstat.m_mtypes[MSG_IOCNAK],
331	  */
332	  mbstat.m_mtypes[MSG_CTL]);
333  return(&mbuf_str[0]);
334}
335
336void trace_beg(str, m)
337     char *str;
338     gbuf_t *m;
339{
340	int i = 0, j = 0;
341	gbuf_t *mdata, *mchain;
342
343	if (m)
344	  for (i = 0, j = 0, mdata = m, mchain = m; mdata; i++) {
345	    mdata = gbuf_cont(mdata);
346	    if (!mdata && mchain) {
347	      mdata = gbuf_next(mchain);
348	      mchain = mdata;
349	      j++;
350	    }
351	  }
352	dPrintf(D_M_ASP, D_L_TRACE,
353		("%s: %s, m# = %d, c# = %d\n", str, mbuf_totals(), i, j));
354}
355
356void trace_end(str)
357     char *str;
358{
359	dPrintf(D_M_ASP, D_L_TRACE,
360		("  %s: %s\n", str, mbuf_totals()));
361}
362#endif /* AT_MBUF_TRACE */
363
364/*
365 * the write routine
366 */
367int asp_wput(gref, m)
368	gref_t *gref;
369	gbuf_t *m;
370{
371	int err;
372	unsigned char sockSav, sock_num;
373	gbuf_t *mioc, *mdata;
374	ioc_t *iocbp;
375	asp_scb_t *scb, *server_scb, *curr_scb;
376	at_inet_t *addr;
377	asp_word_t aw;
378	union asp_primitives *primitives;
379	asp_status_cmd_t *status_cmd;
380	asp_open_cmd_t *open_cmd;
381	at_retry_t Retry;
382
383	scb = (asp_scb_t *)gref->info;
384	if (scb->dflag == 0) {
385		atp_wput(gref, m);
386		return 0;
387	}
388
389	if (gbuf_type(m) != MSG_IOCTL) {
390		dPrintf(D_M_ASP, D_L_WARNING,
391			("asp_wput: UNKNOWN message, type=%d\n",
392			 gbuf_type(m)));
393		gbuf_freem(m);
394		return 0;
395	}
396
397	mioc = m;
398	iocbp = (ioc_t *)gbuf_rptr(mioc);
399
400	dPrintf(D_M_ASP_LOW, D_L_INFO,
401		("asp_wput: %s, loc=%d, state=%s\n",
402		 aspIOCStr(iocbp->ioc_cmd), scb->loc_addr.socket,
403		 aspStateStr(scb->state)));
404
405	switch (iocbp->ioc_cmd) {
406	case ASPIOC_CloseSession:
407		if ((scb->state == ASPSTATE_Close) || (scb->rem_addr.node == 0))
408			break;
409
410		Retry.retries = 3;
411		Retry.interval = 1;
412		aw.func = ASPFUNC_CloseSess;
413		aw.param1 = scb->sess_id;
414		aw.param2 = 0;
415		iocbp->ioc_private = (void *)scb;
416		scb->ioc_wait = (unsigned char)(iocbp->ioc_cmd & 0xff);
417		iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST;
418		asp_send_req(gref, mioc, &scb->rem_addr, &Retry, &aw,
419			     0, ASPSTATE_WaitingForCloseSessRsp, 0x01);
420		return 0;
421
422	case ASPIOC_ClientBind:
423		/*
424		 * open an ATP channel
425		 */
426		if ((err = atp_open(gref, 0)) != 0) {
427			asp_iocnak(gref, mioc, err);
428			return 0;
429		}
430		scb->atp_state = (atp_state_t *)gref->info;
431		scb->atp_state->pid = scb->pid;
432		/*
433		 * bind to any available socket
434		 */
435		scb->dflag = 2;
436		sockSav = scb->dflag;
437		if ((sock_num = (at_socket)atp_bind(gref, 0, &sockSav)) == 0) {
438			scb->atp_state = (atp_state_t *)0;
439			atp_close(gref, 0);
440			gref->info = (void *)scb;
441			asp_iocnak(gref, mioc, EINVAL);
442			return 0;
443		}
444		gref->info = (void *)scb;
445		asp_dequeue_scb(scb);
446		scb->atp_state->dflag = scb->dflag;
447		scb->loc_addr.socket = sock_num;
448		asp_scbQ[sock_num] = scb;
449		asp_inpC[sock_num]++;
450		atp_pidM[sock_num] = 0;
451		break;
452
453	case ASPIOC_ListenerBind:
454		/*
455		 * open an ATP channel
456		 */
457		if ((err = atp_open(gref, 0)) != 0) {
458			asp_iocnak(gref, mioc, err);
459			return 0;
460		}
461		scb->atp_state = (atp_state_t *)gref->info;
462		scb->atp_state->pid = scb->pid;
463		/*
464		 * bind to any available socket
465		 */
466		if ((sock_num = (at_socket)atp_bind(gref, 0, 0)) == 0) {
467			scb->atp_state = (atp_state_t *)0;
468			atp_close(gref, 0);
469			gref->info = (void *)scb;
470			asp_iocnak(gref, mioc, EINVAL);
471			return 0;
472		}
473		gref->info = (void *)scb;
474		asp_dequeue_scb(scb);
475		scb->atp_state->dflag = scb->dflag;
476		scb->loc_addr.socket = sock_num;
477		asp_scbQ[sock_num] = scb;
478		asp_inpC[sock_num]++;
479		if (gbuf_cont(mioc))
480			*(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->loc_addr;
481		break;
482
483	case ASPIOC_GetLocEntity:
484		if ((gbuf_cont(mioc) == 0) || (scb->atp_state == 0)) {
485			asp_iocnak(gref, mioc, EPROTOTYPE);
486			return 0;
487		}
488		*(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->loc_addr;
489		break;
490
491	case ASPIOC_GetRemEntity:
492		if ((gbuf_cont(mioc) == 0) || (scb->atp_state == 0)) {
493			asp_iocnak(gref, mioc, EPROTOTYPE);
494			return 0;
495		}
496		*(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->rem_addr;
497		break;
498
499	case ASPIOC_GetSession:
500		if ((mdata = gbuf_cont(mioc)) == 0) {
501			asp_iocnak(gref, mioc, EPROTOTYPE);
502			return 0;
503		}
504		addr = (at_inet_t *)gbuf_rptr(mdata);
505		scb->tickle_interval = (unsigned short)addr->node;
506		scb->session_timer = addr->net;
507		server_scb = asp_scbQ[addr->socket];
508/*### LD 10/28/97: changed to make sure we're not accessing a null server_scb */
509		if (server_scb == 0) {
510			asp_iocnak(gref, mioc, EPROTOTYPE);
511			return 0;
512		}
513		if (server_scb->sess_ioc == 0) {
514			asp_iocnak(gref, mioc, EPROTOTYPE);
515			return 0;
516		}
517
518		/*
519		 * open an ATP channel
520		 */
521		if ((err = atp_open(gref, 0)) != 0) {
522			gref->info = (void *)scb;
523			asp_iocnak(gref, mioc, err);
524			return 0;
525		}
526		scb->atp_state = (atp_state_t *)gref->info;
527		scb->atp_state->pid = scb->pid;
528		/*
529		 * bind to any available socket
530		 */
531		scb->dflag = 3;
532		sockSav = scb->dflag;
533		if ((sock_num = (at_socket)atp_bind(gref, 0, &sockSav)) == 0) {
534			atp_close(gref, 0);
535			asp_dequeue_scb(scb);
536			sock_num = sockSav;
537			scb->loc_addr.socket = sock_num;
538			for (curr_scb = asp_scbQ[sock_num];
539				curr_scb->next_scb; curr_scb = curr_scb->next_scb) ;
540			scb->prev_scb = curr_scb;
541			curr_scb->next_scb = scb;
542			scb->atp_state = curr_scb->atp_state;
543		} else {
544			asp_dequeue_scb(scb);
545			scb->loc_addr.socket = sock_num;
546			asp_scbQ[sock_num] = scb;
547			scb->atp_state->dflag = scb->dflag;
548		}
549		gref->info = (void *)scb;
550		asp_inpC[sock_num]++;
551		gbuf_cont(mioc) = 0;
552		asp_accept(server_scb, scb, mdata);
553		break;
554
555	case ASPIOC_GetStatus:
556		if ((mdata = gbuf_cont(mioc)) == 0) {
557			asp_iocnak(gref, mioc, EINVAL);
558			return 0;
559		}
560		gbuf_cont(mioc) = 0;
561		status_cmd = (asp_status_cmd_t *)gbuf_rptr(mdata);
562		aw.func = ASPFUNC_GetStatus;
563		aw.param1 = 0;
564		aw.param2 = 0;
565		scb->ioc_wait = (unsigned char)(iocbp->ioc_cmd & 0xff);
566		iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF;
567		/* bms:  make sure this is an ALO request */
568		asp_send_req(gref, mioc, &status_cmd->SLSEntityIdentifier,
569			     &status_cmd->Retry, &aw, 0, ASPSTATE_WaitingForGetStatusRsp, 0xff);
570		gbuf_freeb(mdata);
571		return 0;
572
573	case ASPIOC_OpenSession:
574		if ((mdata = gbuf_cont(mioc)) == 0) {
575			asp_iocnak(gref, mioc, EINVAL);
576			return 0;
577		}
578		gbuf_cont(mioc) = 0;
579		open_cmd = (asp_open_cmd_t *)gbuf_rptr(mdata);
580		scb->svc_addr = open_cmd->SLSEntityIdentifier;
581		scb->rem_addr = scb->svc_addr;
582		scb->rem_node = scb->rem_addr.node;
583		scb->rem_addr.node = 0;
584		scb->tickle_interval = open_cmd->TickleInterval;
585		scb->session_timer = open_cmd->SessionTimer;
586		aw.func = ASPFUNC_OpenSess;
587		aw.param1 = scb->loc_addr.socket;
588		aw.param2 = htons(ASP_Version);
589		scb->ioc_wait = (unsigned char)(iocbp->ioc_cmd & 0xff);
590		iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF;
591		asp_send_req(gref, mioc, &open_cmd->SLSEntityIdentifier,
592			     &open_cmd->Retry, &aw, 1, ASPSTATE_WaitingForOpenSessRsp, 0x01);
593		gbuf_freeb(mdata);
594		return 0;
595
596	case ASPIOC_StatusBlock:
597		/*
598		 * save the server status block
599		 */
600	  if (scb->stat_msg)
601			gbuf_freem(scb->stat_msg);
602	  scb->stat_msg = gbuf_cont(mioc);
603	  gbuf_cont(mioc) = 0;
604	  break;
605
606	  /* *** Does scb->pid get used in a packet header,
607		 and if so is it in ASP, or in ATP?
608		 If not, do we need this call for anything?
609		 (cap does currently use it in _ANS code.)
610	     *** */
611	case ASPIOC_SetPid:
612		if (gbuf_cont(mioc) == 0) {
613			asp_iocnak(gref, mioc, EINVAL);
614			return 0;
615		}
616		scb->pid = *(int *)gbuf_rptr(gbuf_cont(mioc));
617		break;
618
619	case ASPIOC_GetSessId:
620		if (gbuf_cont(mioc) == 0) {
621			asp_iocnak(gref, mioc, EINVAL);
622			return 0;
623		}
624		*(gref_t **)gbuf_rptr(gbuf_cont(mioc)) = gref;
625		break;
626
627	case ASPIOC_Look:
628		if (gbuf_cont(mioc) == 0) {
629			asp_iocnak(gref, mioc, EINVAL);
630			return 0;
631		}
632		if (scb->sess_ioc) {
633			primitives = (union asp_primitives *)gbuf_rptr(scb->sess_ioc);
634			if (primitives->Primitive == ASPFUNC_CmdReply)
635				*(int *)gbuf_rptr(gbuf_cont(mioc)) = 0;
636			else
637				*(int *)gbuf_rptr(gbuf_cont(mioc)) = 1;
638		} else
639			*(int *)gbuf_rptr(gbuf_cont(mioc)) = -1;
640		break;
641
642	case DDP_IOC_GET_CFG:
643		{
644		struct atp_state *atp = (struct atp_state *)gref->info;
645		if (atp->dflag)
646			atp = (struct atp_state *)atp->atp_msgq;
647
648		if (gbuf_cont(mioc) == 0) {
649			asp_iocnak(gref, mioc, EINVAL);
650			return 0;
651		}
652		/* *** borrowed from ddp_proto.c to handle DDP_IOC_GET_CFG
653		       on atp fd *** */
654		scb->state = ASPSTATE_Idle;
655		{
656		/* *** was ddp_get_cfg() *** */
657		  ddp_addr_t *cfgp =
658		    (ddp_addr_t *)gbuf_rptr(gbuf_cont(mioc));
659		  cfgp->inet.net = ifID_home->ifThisNode.s_net;
660		  cfgp->inet.node = ifID_home->ifThisNode.s_node;
661		  cfgp->inet.socket = atp->atp_socket_no;
662		  cfgp->ddptype = DDP_ATP;
663		}
664		gbuf_wset(gbuf_cont(mioc), sizeof(at_inet_t));
665		}
666		break;
667
668	default:
669		asp_iocnak(gref, mioc, EINVAL);
670		return 0;
671	}
672
673	asp_iocack(gref, mioc);
674	return 0;
675} /* asp_wput */
676
677/*
678 * send request routine
679 */
680StaticProc int
681asp_send_req(gref, mioc, dest, retry, awp, xo, state, bitmap)
682	gref_t *gref;
683	gbuf_t *mioc;
684	at_inet_t *dest;
685	at_retry_t *retry;
686	asp_word_t *awp;
687	unsigned char xo;
688	unsigned char state;
689	unsigned char bitmap;
690{
691	int i;
692	gbuf_t *mdata;
693	ioc_t *iocbp;
694	struct atp_set_default *sd;
695	at_ddp_t *ddp;
696	at_atp_t *atp;
697	struct atpBDS *atpBDS;
698	asp_scb_t *scb = (asp_scb_t *)gref->info;
699
700	/*
701	 * allocate an ATP buffer for the request
702	 */
703	if ((gbuf_cont(mioc) = gbuf_alloc(aspCMDsize, PRI_MED)) == 0) {
704		if (awp->func == ASPFUNC_Tickle)
705			gbuf_freem(mioc);
706		else
707			asp_iocnak(gref, mioc, ENOBUFS);
708		dPrintf(D_M_ASP, D_L_WARNING,
709		("asp_send_req: ENOBUFS, loc=%d\n", scb->loc_addr.socket));
710
711		return -1;
712	}
713	mdata = gbuf_cont(mioc);
714	iocbp = (ioc_t *)gbuf_rptr(mioc);
715
716	/*
717	 * build the request
718	 */
719	atpBDS = (struct atpBDS *)gbuf_rptr(mdata);
720	gbuf_wset(mdata,atpBDSsize);
721	for (i=0; i < ATP_TRESP_MAX; i++) {
722		*(unsigned long  *)atpBDS[i].bdsBuffAddr = 1;
723		*(unsigned short *)atpBDS[i].bdsBuffSz = ATP_DATA_SIZE;
724	}
725	sd = (struct atp_set_default *)gbuf_wptr(mdata);
726	gbuf_winc(mdata,sizeof(struct atp_set_default));
727	sd->def_retries = (retry->retries == -1) ?
728		ATP_INFINITE_RETRIES : retry->retries;
729	sd->def_rate = retry->interval*TICKS_PER_SEC;
730	sd->def_BDSlen = atpBDSsize;
731	ddp = (at_ddp_t *)gbuf_wptr(mdata);
732	NET_ASSIGN(ddp->src_net, scb->loc_addr.net);
733	ddp->src_node = scb->loc_addr.node;
734	NET_ASSIGN(ddp->dst_net, dest->net);
735	ddp->dst_node = dest->node;
736	ddp->dst_socket = dest->socket;
737	UAS_ASSIGN(ddp->checksum, 0);
738	atp = ATP_ATP_HDR(gbuf_wptr(mdata));
739	atp->xo = xo;
740	atp->xo_relt = xo;
741	atp->bitmap = bitmap;
742	gbuf_winc(mdata,TOTAL_ATP_HDR_SIZE);
743	*(asp_word_t *)atp->user_bytes = *awp;
744	iocbp->ioc_count = gbuf_len(mdata);
745	iocbp->ioc_rval = 0;
746
747	/*
748	 * send the request
749	 */
750	scb->state = state;
751	dPrintf(D_M_ASP, D_L_INFO,
752		("asp_send_req: %s, loc=%d, rem= %d, len=%d, state=%s\n",
753		 aspCmdStr(awp->func),
754		 scb->loc_addr.socket, ddp->dst_socket, iocbp->ioc_count,
755		 aspStateStr(scb->state)));
756
757	atp_send_req(gref, mioc);
758	return 0;
759}
760
761/*
762 * send tickle routine - locked version
763 */
764StaticProc void
765asp_send_tickle_locked(scb)
766	void *scb;
767{
768	atalk_lock();
769	asp_send_tickle((asp_scb_t *)scb);
770	atalk_unlock();
771}
772
773
774/*
775 * send tickle routine
776 */
777StaticProc void
778asp_send_tickle(scb)
779	asp_scb_t *scb;
780{
781	gbuf_t *mioc;
782	at_retry_t retry;
783	asp_word_t aw;
784	at_inet_t *dest;
785
786
787	/*
788	 * make sure the connection is still there
789	 */
790	if (scb->rem_addr.node == 0) {
791		return;
792        }
793
794	if ((mioc = gbuf_alloc(sizeof(ioc_t), PRI_HI)) == 0) {
795		dPrintf(D_M_ASP, D_L_WARNING,
796		("asp_send_tickle: ENOBUFS 0, loc=%d, rem=%d\n",
797			scb->loc_addr.socket,scb->rem_addr.socket));
798		timeout(asp_send_tickle_locked, (void *)scb, 10);
799		return;
800	}
801	gbuf_wset(mioc,sizeof(ioc_t));
802	gbuf_set_type(mioc, MSG_IOCTL);
803
804	dest = scb->svc_addr.node ?
805		(at_inet_t *)&scb->svc_addr : (at_inet_t *)&scb->rem_addr;
806	retry.interval = scb->tickle_interval;
807	retry.retries  = -1;
808	retry.backoff  = 1;
809	aw.func = ASPFUNC_Tickle;
810	aw.param1 = scb->sess_id;
811	aw.param2 = 0;
812	((ioc_t *)gbuf_rptr(mioc))->ioc_cr = (void *)scb;
813	((ioc_t *)gbuf_rptr(mioc))->ioc_cmd = AT_ATP_ISSUE_REQUEST_TICKLE;
814
815	if (asp_send_req(scb->gref, mioc, dest, &retry, &aw, 0, scb->state, 0)) {
816		dPrintf(D_M_ASP, D_L_WARNING,
817			("asp_send_tickle: ENOBUFS 1, loc=%d, rem=%d\n",
818			 scb->loc_addr.socket,scb->rem_addr.socket));
819
820		timeout(asp_send_tickle_locked, (void *)scb, 10);
821		return;
822	}
823}
824
825/*
826 * accept connection routine
827 */
828StaticProc void
829asp_accept(scb, sess_scb, m)
830	asp_scb_t *scb;
831	asp_scb_t *sess_scb;
832	gbuf_t *m;
833{
834	gbuf_t *mdata;
835	at_ddp_t *ddp;
836	at_atp_t *atp;
837	asp_word_t *awp;
838	at_inet_t rem_addr;
839
840	mdata = scb->sess_ioc;
841	ddp = (at_ddp_t *)gbuf_rptr(mdata);
842	atp = (at_atp_t *)(gbuf_rptr(mdata) + DDP_X_HDR_SIZE);
843	rem_addr.net = NET_VALUE(ddp->src_net);
844	rem_addr.node = ddp->src_node;
845	rem_addr.socket = ddp->src_socket;
846	awp = (asp_word_t *)atp->user_bytes;
847
848	sess_scb->loc_addr.net = NET_VALUE(ddp->dst_net);
849	sess_scb->loc_addr.node = ddp->dst_node;
850	NET_ASSIGN(ddp->src_net, sess_scb->loc_addr.net);
851	ddp->src_node = sess_scb->loc_addr.node;
852	NET_ASSIGN(ddp->dst_net, rem_addr.net);
853	ddp->dst_node = rem_addr.node;
854	ddp->dst_socket = rem_addr.socket;
855
856	sess_scb->sess_id = sess_scb->loc_addr.socket;
857	sess_scb->rem_socket = rem_addr.socket;
858	sess_scb->rem_addr = rem_addr;
859	sess_scb->rem_addr.socket = awp->param1;
860	sess_scb->reply_socket = sess_scb->rem_addr.socket;
861	awp->func = sess_scb->loc_addr.socket;
862	awp->param1 = sess_scb->sess_id;
863	awp->param2 = 0;
864	gbuf_freeb(m);
865	scb->sess_ioc = gbuf_next(mdata);
866	gbuf_next(mdata) = 0;
867	asp_timout(asp_hangup, sess_scb, sess_scb->session_timer);
868	atp_send_rsp(scb->gref, mdata, TRUE);
869	asp_send_tickle(sess_scb);
870	dPrintf(D_M_ASP, D_L_INFO,
871		("asp_accept: ACCEPT connect request, loc=%d, rem=%x.%x.%d\n",
872		sess_scb->loc_addr.socket,
873		sess_scb->rem_addr.net,
874		sess_scb->rem_addr.node,sess_scb->rem_addr.socket));
875} /* asp_accept */
876
877/*
878 * timer routine - locked version
879 */
880void asp_clock_locked(arg)
881	void *arg;
882{
883	atalk_lock();
884	asp_clock(arg);
885	atalk_unlock();
886}
887
888/*
889 * timer routine
890 */
891void asp_clock(arg)
892	void *arg;
893{
894	asp_scb_t *scb;
895	asp_tmo_func tmo_func;
896
897	if (scb_tmo_list)
898		scb_tmo_list->tmo_delta--;
899	while (((scb = scb_tmo_list) != 0) && (scb_tmo_list->tmo_delta == 0)) {
900		if ((scb_tmo_list = scb->next_tmo) != 0)
901			scb_tmo_list->prev_tmo = 0;
902		if ((tmo_func = scb->tmo_func) != 0) {
903			scb->tmo_func = 0;
904			(*tmo_func)(scb);
905		}
906	}
907
908	if (++scb_tmo_cnt == 0) scb_tmo_cnt++;
909	timeout(asp_clock_locked, (void *)arg, (1<<SESS_TMO_RES)*TICKS_PER_SEC);
910
911}
912
913/*
914 * ACK reply routine
915 */
916void
917asp_ack_reply(gref, mioc)
918	register gref_t *gref;
919	register gbuf_t *mioc;
920{
921	int len, msize, nbds;
922	register gbuf_t *mdata, *m, *mx;
923	struct atpBDS *atpBDS;
924	at_ddp_t *ddp;
925	at_atp_t *atp;
926	register asp_scb_t *scb, *sess_scb;
927	register ioc_t *iocbp;
928	register asp_word_t *awp;
929	register asp_command_ind_t *command_ind;
930	register asp_cmdreply_ind_t *cmdreply_ind;
931	at_inet_t rem_addr;
932
933	iocbp = (ioc_t *)gbuf_rptr(mioc);
934
935	if (iocbp->ioc_cmd == AT_ATP_ISSUE_REQUEST_TICKLE) {
936		/*
937		 * ignore the ack for the tickle request
938		 */
939		scb = (asp_scb_t *)iocbp->ioc_cr;
940		scb->tickle_tid = (unsigned short)iocbp->ioc_rval;
941		gbuf_freem(mioc);
942		return;
943	}
944
945	scb = (asp_scb_t *)gref->info;
946	if (scb == 0) {
947		gbuf_freem(mioc);
948		return;
949	}
950
951	if (iocbp->ioc_cmd == AT_ATP_GET_POLL) {
952		/*
953		 * if no data, just drop the request
954		 */
955		if ((mdata = gbuf_cont(mioc)) == 0) {
956			gbuf_freeb(mioc);
957			return;
958		}
959
960		gbuf_set_type(mioc, MSG_IOCTL);
961		ddp = (at_ddp_t *)gbuf_rptr(mdata);
962		gbuf_rinc(mdata,DDP_X_HDR_SIZE);
963		atp = (at_atp_t *)gbuf_rptr(mdata);
964		gbuf_rinc(mdata,ATP_HDR_SIZE);
965		rem_addr.net = NET_VALUE(ddp->src_net);
966		rem_addr.node = ddp->src_node;
967		rem_addr.socket = ddp->src_socket;
968		awp = (asp_word_t *)atp->user_bytes;
969
970		if (scb->next_scb) {
971			/*
972			 * find the responsible scb
973			 */
974			if ((scb = asp_find_scb(scb->loc_addr.socket, &rem_addr)) == 0) {
975				gbuf_freem(mioc);
976				return;
977			}
978		}
979		dPrintf(D_M_ASP, D_L_INFO,
980			("asp_ack_reply: %s, loc=%d, rem=%x.%x.%d\n",
981			aspCmdStr(awp->func),scb->loc_addr.socket,
982			NET_VALUE(ddp->src_net) ,ddp->src_node,ddp->src_socket));
983
984		if (scb->rem_addr.node)
985			asp_untimout(asp_hangup, scb);
986
987		switch (awp->func) {
988		case ASPFUNC_GetStatus:
989			/*
990			 * ignore if this is not a server socket
991			 */
992			mx = 0;
993			if ((scb->dflag != 1) || (scb->stat_msg
994					&& ((mx = gbuf_dupb(scb->stat_msg)) == 0)))
995				break;
996			gbuf_freeb(mioc);
997
998			/*
999			 * send the status block
1000			 */
1001			if (gbuf_cont(mdata)) {
1002				gbuf_freem(gbuf_cont(mdata));
1003				gbuf_cont(mdata) = 0;
1004			}
1005			gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE);
1006			if ((m = gbuf_alloc( (TOTAL_ATP_HDR_SIZE+atpBDSsize), PRI_MED)) == 0) {
1007				gbuf_freem(mdata);
1008				gbuf_freeb(mx);
1009				goto l_done;
1010			}
1011			bcopy(gbuf_rptr(mdata), gbuf_rptr(m), TOTAL_ATP_HDR_SIZE);
1012			gbuf_freeb(mdata);
1013			mdata = m;
1014			ddp = (at_ddp_t *)gbuf_rptr(mdata);
1015			gbuf_wset(mdata,DDP_X_HDR_SIZE);
1016			atp = (at_atp_t *)gbuf_wptr(mdata);
1017			gbuf_winc(mdata,ATP_HDR_SIZE);
1018			awp = (asp_word_t *)atp->user_bytes;
1019			NET_NET(ddp->src_net, ddp->dst_net);
1020			ddp->src_node = ddp->dst_node;
1021			NET_ASSIGN(ddp->dst_net, rem_addr.net);
1022			ddp->dst_node = rem_addr.node;
1023			ddp->dst_socket = rem_addr.socket;
1024			UAS_ASSIGN(ddp->checksum, 0);
1025			atpBDS = (struct atpBDS *)gbuf_wptr(mdata);
1026			msize = mx ? gbuf_msgsize(mx) : 0;
1027			for (nbds=0; (nbds < ATP_TRESP_MAX) && (msize > 0); nbds++) {
1028				len = msize < ATP_DATA_SIZE ? msize : ATP_DATA_SIZE;
1029				msize -= ATP_DATA_SIZE;
1030				*(long *)atpBDS[nbds].bdsUserData = 0;
1031				UAL_ASSIGN(atpBDS[nbds].bdsBuffAddr, 1);
1032				UAS_ASSIGN(atpBDS[nbds].bdsBuffSz, len);
1033			}
1034			UAS_ASSIGN(atpBDS[0].bdsDataSz, nbds);
1035			gbuf_winc(mdata,atpBDSsize);
1036			gbuf_cont(mdata) = mx;
1037			atp_send_rsp(gref, mdata, FALSE);
1038			goto l_done;
1039
1040		case ASPFUNC_OpenSess:
1041			/*
1042			 * ignore if server is not ready
1043			 */
1044			if ((scb->dflag != 1) || (scb->stat_msg == 0))
1045				break;
1046			gbuf_freeb(mioc);
1047
1048			if (gbuf_cont(mdata)) {
1049				gbuf_freem(gbuf_cont(mdata));
1050				gbuf_cont(mdata) = 0;
1051			}
1052			gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE);
1053			gbuf_wset(mdata,TOTAL_ATP_HDR_SIZE);
1054			if (awp->param2 != ASP_Version) {
1055				/*
1056				 * bad version number, send the OpenSession response
1057				 */
1058				awp->func = 0;
1059				awp->param1 = 0;
1060				awp->param2 = htons((unsigned short)ASPERR_BadVersNum);
1061				dPrintf(D_M_ASP, D_L_INFO,
1062					("             : version=%d\n",
1063					ASPERR_BadVersNum));
1064
1065				NET_NET(ddp->src_net, ddp->dst_net);
1066				ddp->src_node = ddp->dst_node;
1067				NET_ASSIGN(ddp->dst_net, rem_addr.net);
1068				ddp->dst_node = rem_addr.node;
1069				ddp->dst_socket = rem_addr.socket;
1070				atp_send_rsp(gref, mdata, FALSE);
1071				return;
1072			}
1073
1074			/*
1075			 * queue the connection request
1076			 */
1077			gbuf_next(mdata) = 0;
1078			if ((m = scb->sess_ioc) == 0) {
1079				scb->sess_ioc = mdata;
1080				if (scb->get_wait)
1081					wakeup(&scb->event);
1082				else
1083					atalk_notify_sel(gref);
1084			} else {
1085				while (gbuf_next(m))
1086					m = gbuf_next(m);
1087				gbuf_next(m) = mdata;
1088			}
1089			dPrintf(D_M_ASP, D_L_INFO,
1090				("             : QUEUE connect request\n"));
1091
1092			return;
1093
1094		case ASPFUNC_Command:
1095		case ASPFUNC_Write:
1096			if ( (scb->sess_id != awp->param1)
1097			     || (scb->rcv_seq_num != ntohs(awp->param2))
1098			     || BAD_REMADDR(rem_addr) ) {
1099				char era[8], ra[8];
1100				snprintf(era, sizeof(era), "%d.%d", scb->rem_addr.node,scb->rem_addr.socket);
1101				snprintf(ra, sizeof(ra), "%d.%d", rem_addr.node,rem_addr.socket);
1102				dPrintf(D_M_ASP, D_L_WARNING,
1103					("             : DROP, id=%d,esn=%d,sn=%d,erem=%s,rem=%s\n",
1104					scb->sess_id,scb->rcv_seq_num,awp->param2,era,ra));
1105				gbuf_cont(mioc) = 0;
1106				gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE);
1107				atp_drop_req(gref, mdata);
1108				break;
1109			}
1110			scb->reply_socket = rem_addr.socket;
1111			if (awp->func == ASPFUNC_Write)
1112				scb->wrt_seq_num = scb->rcv_seq_num;
1113			NEXT_SEQ_NUM(scb->rcv_seq_num);
1114			gbuf_set_type(mioc, MSG_PROTO);
1115			gbuf_wset(mioc,sizeof(asp_command_ind_t));
1116			command_ind = (asp_command_ind_t *)gbuf_rptr(mioc);
1117			command_ind->Primitive = (int)awp->func;
1118			command_ind->ReqRefNum =
1119				ntohs(*(unsigned short *)atp->tid);
1120			command_ind->ReqType = awp->func;
1121
1122			mdata = gbuf_strip(mdata);
1123			gbuf_cont(mioc) = mdata;
1124			if (scb->req_flag) {
1125				if ((mx = scb->req_msgq) != 0) {
1126					while (gbuf_next(mx))
1127						mx = gbuf_next(mx);
1128					gbuf_next(mx) = mioc;
1129				} else
1130					scb->req_msgq = mioc;
1131			} else {
1132				scb->req_flag = 1;
1133				asp_putnext(scb->gref, mioc);
1134			}
1135			goto l_done;
1136
1137		case ASPFUNC_WriteContinue:
1138			if ( (scb->sess_id != awp->param1)
1139			     || (scb->snd_seq_num != awp->param2)
1140			     || BAD_REMADDR(rem_addr) ) {
1141				break;
1142			}
1143			scb->reply_socket = rem_addr.socket;
1144			gbuf_set_type(mioc, MSG_PROTO);
1145			gbuf_wset(mioc,sizeof(asp_command_ind_t));
1146			command_ind = (asp_command_ind_t *)gbuf_rptr(mioc);
1147			command_ind->Primitive = (int)awp->func;
1148			command_ind->ReqRefNum =
1149				ntohs(*(unsigned short *)atp->tid);
1150			command_ind->ReqType = awp->func;
1151
1152			mdata = gbuf_strip(mdata);
1153			gbuf_cont(mioc) = mdata;
1154			asp_putnext(scb->gref, mioc);
1155			goto l_done;
1156
1157		case ASPFUNC_Tickle:
1158			if (scb->stat_msg) {
1159				sess_scb = asp_scbQ[awp->param1];
1160				if (sess_scb && sess_scb->next_scb)
1161					sess_scb = asp_find_scb(
1162						sess_scb->loc_addr.socket, &rem_addr);
1163				if (sess_scb) {
1164				if (sess_scb->rem_addr.node)
1165					asp_untimout(asp_hangup, sess_scb);
1166				if (sess_scb->rem_addr.node)
1167					asp_timout(asp_hangup, sess_scb, sess_scb->session_timer);
1168				}
1169			}
1170			dPrintf(D_M_ASP, D_L_INFO,
1171				("             : Tickle, %d -> %d, id=%d\n",
1172				ddp->src_socket,ddp->dst_socket,awp->param1));
1173			break;
1174
1175		case ASPFUNC_CloseSess:
1176			if ( (scb->sess_id != awp->param1)
1177			     || (scb->state == ASPSTATE_Close)
1178			     || (scb->state == ASPSTATE_WaitingForCloseSessRsp)
1179			     || (scb->rem_addr.net != rem_addr.net)
1180			     || (scb->rem_addr.node != rem_addr.node) ) {
1181				dPrintf(D_M_ASP, D_L_INFO,
1182					("             : CLOSE retry, loc=%d, rem=%x.%x.%d\n",
1183					scb->loc_addr.socket,
1184					scb->rem_addr.net,
1185					scb->rem_addr.node,
1186					scb->rem_addr.socket));
1187
1188				break;
1189			}
1190			gbuf_freeb(mioc);
1191
1192			/*
1193			 * build the CloseSess response to be sent to peer
1194			 * when the session is closed by the user.
1195			 */
1196			if (gbuf_cont(mdata)) {
1197				gbuf_freem(gbuf_cont(mdata));
1198				gbuf_cont(mdata) = 0;
1199			}
1200			gbuf_rdec(mdata,TOTAL_ATP_HDR_SIZE);
1201			gbuf_wset(mdata,TOTAL_ATP_HDR_SIZE);
1202			NET_NET(ddp->src_net, ddp->dst_net);
1203			ddp->src_node = ddp->dst_node;
1204			NET_ASSIGN(ddp->dst_net, rem_addr.net);
1205			ddp->dst_node = rem_addr.node;
1206			ddp->dst_socket = rem_addr.socket;
1207			awp->func = 0;
1208			awp->param1 = 0;
1209			awp->param2 = 0;
1210			dPrintf(D_M_ASP,D_L_INFO,
1211				("             : CLOSE, loc=%d, rem=%x.%x.%d\n",
1212				scb->loc_addr.socket,
1213				scb->rem_addr.net,
1214				scb->rem_addr.node,
1215				scb->rem_addr.socket));
1216
1217			gbuf_next(mdata) = 0;
1218			if (scb->sess_ioc)
1219				gbuf_freel(scb->sess_ioc);
1220			scb->sess_ioc = mdata;
1221			scb->state = ASPSTATE_Close;
1222
1223			/*
1224			 * notify upstream of the CloseSess from peer
1225			 */
1226			asp_hangup(scb);
1227			return;
1228
1229		case ASPFUNC_Attention:
1230			if ( (scb->sess_id != awp->param1)
1231			     || (scb->rem_addr.net != rem_addr.net)
1232			     || (scb->rem_addr.node != rem_addr.node) ) {
1233				break;
1234			}
1235			gbuf_set_type(mioc, MSG_PROTO);
1236			gbuf_wset(mioc,sizeof(asp_command_ind_t));
1237			command_ind = (asp_command_ind_t *)gbuf_rptr(mioc);
1238			command_ind->Primitive = (int)awp->func;
1239			command_ind->ReqRefNum =
1240				ntohs(*(unsigned short *)atp->tid);
1241			command_ind->ReqType = awp->func;
1242			scb->attn_tid = *(unsigned short *)atp->tid;
1243			scb->attn_flag = 1;
1244			gbuf_rdec(mdata,2); /* attention code */
1245
1246			mdata = gbuf_strip(mdata);
1247			gbuf_cont(mioc) = mdata;
1248			asp_putnext(scb->gref, mioc);
1249			goto l_done;
1250
1251		default:
1252			dPrintf(D_M_ASP, D_L_WARNING,
1253				("             : UNKNOWN func, func=%d\n",
1254				awp->func));
1255
1256			break;
1257		}
1258	}
1259
1260	else if (iocbp->ioc_cmd == AT_ATP_REQUEST_COMPLETE) {
1261		if (scb->next_scb) {
1262			/*
1263			 * find the responsible scb
1264			 */
1265			scb = (asp_scb_t *)iocbp->ioc_private;
1266			if ((scb == 0) || (scb->magic_num != 222)) {
1267				dPrintf(D_M_ASP, D_L_ERROR,
1268					("asp_ack_reply: CAN'T find scb 1\n"));
1269				gbuf_freem(mioc);
1270				return;
1271			}
1272		}
1273		dPrintf(D_M_ASP, D_L_INFO,
1274			("asp_ack_reply: RSP, loc=%d, rem=%x.%x.%d, state=%s\n",
1275			scb->loc_addr.socket,
1276			scb->rem_addr.net,
1277			scb->rem_addr.node,
1278			scb->rem_addr.socket,
1279			aspStateStr(scb->state)));
1280
1281		switch (scb->state) {
1282		case ASPSTATE_Close:
1283		case ASPSTATE_Idle:
1284			scb->rem_addr.node = 0;
1285			gbuf_freem(mioc);
1286			if (scb->get_wait)
1287				wakeup(&scb->event);
1288			else
1289				atalk_notify_sel(gref);
1290			return;
1291
1292		case ASPSTATE_WaitingForGetStatusRsp:
1293			scb->ioc_wait = 0;
1294			scb->state = ASPSTATE_Idle;
1295			mx = gbuf_cont(mioc);
1296			gbuf_cont(mioc) = 0;
1297			mdata = gbuf_cont(mx);
1298			gbuf_cont(mx) = 0;
1299			iocbp->ioc_cmd = ASPIOC_GetStatus;
1300			iocbp->ioc_count = 0;
1301			iocbp->ioc_rval = mdata ? gbuf_msgsize(mdata) : 0;
1302			gbuf_freeb(mx);
1303			atalk_putnext(gref, mioc);
1304			atalk_putnext(gref, mdata);
1305			return;
1306
1307		case ASPSTATE_WaitingForOpenSessRsp:
1308			scb->ioc_wait = 0;
1309			scb->state = ASPSTATE_Idle;
1310			mx = gbuf_cont(mioc);
1311			gbuf_cont(mioc) = 0;
1312			if (gbuf_cont(mx)) {
1313				gbuf_freem(gbuf_cont(mx));
1314				gbuf_cont(mx) = 0;
1315			}
1316			iocbp->ioc_cmd = ASPIOC_OpenSession;
1317			iocbp->ioc_rval = 0;
1318			iocbp->ioc_count = 0;
1319			atpBDS = (struct atpBDS *)gbuf_rptr(mx);
1320			awp = (asp_word_t *)atpBDS->bdsUserData;
1321			if (awp->param2) {
1322				gbuf_freeb(mx);
1323				asp_iocnak(gref, mioc, ECONNREFUSED);
1324			} else {
1325				scb->rem_addr.node = scb->rem_node;
1326				scb->rem_addr.socket = awp->func;
1327				/* bms:  need to set the reply_socket for client side too.
1328				This makes ALO atten replies sent by the client work. */
1329				scb->reply_socket = scb->rem_addr.socket;
1330				scb->sess_id = awp->param1;
1331				gbuf_freeb(mx);
1332				atalk_putnext(gref, mioc);
1333				asp_timout(asp_hangup, scb, scb->session_timer);
1334				asp_send_tickle(scb);
1335				dPrintf(D_M_ASP, D_L_INFO,
1336					("asp_ack_reply: CONNECT, loc=%d, rem=%x.%x.%d\n",
1337					scb->loc_addr.socket,
1338					scb->rem_addr.net,
1339					scb->rem_addr.node,
1340					scb->rem_addr.socket));
1341			}
1342			return;
1343
1344		case ASPSTATE_WaitingForCommandRsp:
1345		case ASPSTATE_WaitingForWriteRsp:
1346		case ASPSTATE_WaitingForWriteContinueRsp:
1347			if (scb->rem_addr.node)
1348				asp_untimout(asp_hangup, scb);
1349			NEXT_SEQ_NUM(scb->snd_seq_num);
1350			scb->state = ASPSTATE_Idle;
1351			gbuf_set_type(mioc, MSG_PROTO);
1352			mx = gbuf_cont(mioc);
1353			mdata = gbuf_cont(mx);
1354			gbuf_cont(mioc) = mdata;
1355			atpBDS = (struct atpBDS *)gbuf_rptr(mx);
1356			cmdreply_ind = (asp_cmdreply_ind_t *)gbuf_rptr(mioc);
1357			cmdreply_ind->Primitive = ASPFUNC_CmdReply;
1358			cmdreply_ind->CmdResult = ntohl(*(int *)atpBDS->bdsUserData);
1359			gbuf_wset(mioc,sizeof(asp_cmdreply_ind_t));
1360			gbuf_freeb(mx);
1361			asp_putnext(scb->gref, mioc);
1362			goto l_done;
1363
1364		case ASPSTATE_WaitingForCloseSessRsp:
1365			scb->ioc_wait = 0;
1366			scb->state = ASPSTATE_Close;
1367			scb->rem_addr.node = 0;
1368			iocbp->ioc_cmd = ASPIOC_CloseSession;
1369			iocbp->ioc_rval = 0;
1370			if (gbuf_cont(mioc)) {
1371				gbuf_freem(gbuf_cont(mioc));
1372				gbuf_cont(mioc) = 0;
1373			}
1374			atalk_putnext(scb->gref, mioc);
1375			atp_cancel_req(scb->gref, (unsigned int)scb->tickle_tid);
1376			scb->tickle_tid = 0;
1377			return;
1378
1379		default:
1380			dPrintf(D_M_ASP, D_L_WARNING,
1381			("             : UNKNOWN state, state=%s\n",
1382			 aspStateStr(scb->state)));
1383			break;
1384		}
1385	}
1386
1387	else {
1388		if (scb->next_scb) {
1389			/*
1390			 * find the responsible scb
1391			 */
1392			scb = (asp_scb_t *)iocbp->ioc_cr;
1393			if ((scb == 0) || (scb->magic_num != 222)) {
1394				dPrintf(D_M_ASP, D_L_ERROR,
1395					("asp_ack_reply: CAN'T find scb 2\n"));
1396				gbuf_freem(mioc);
1397				return;
1398			}
1399		}
1400
1401		switch (scb->state) {
1402		case ASPSTATE_Close:
1403			scb->rem_addr.node = 0;
1404			break;
1405		}
1406	}
1407
1408	if (mioc != 0)
1409		gbuf_freem(mioc);
1410
1411l_done:
1412	if (scb->rem_addr.node)
1413		asp_timout(asp_hangup, scb, scb->session_timer);
1414} /* asp_ack_reply */
1415
1416/*
1417 * NAK reply routine
1418 */
1419void
1420asp_nak_reply(gref, mioc)
1421	register gref_t *gref;
1422	register gbuf_t *mioc;
1423{
1424	register asp_scb_t *scb;
1425	register ioc_t *iocbp;
1426
1427	iocbp = (ioc_t *)gbuf_rptr(mioc);
1428
1429	if (iocbp->ioc_cmd == AT_ATP_ISSUE_REQUEST_TICKLE) {
1430		/*
1431		 * no tickle, close session
1432		 */
1433		scb = (asp_scb_t *)iocbp->ioc_cr;
1434		gbuf_freem(mioc);
1435		asp_hangup(scb);
1436		dPrintf(D_M_ASP, D_L_WARNING,
1437			("tickle_nak: loc=%d, rem=%x.%x.%d, state=%s\n",
1438			scb->loc_addr.socket,
1439			scb->rem_addr.net,
1440			scb->rem_addr.node,
1441			scb->rem_addr.socket,
1442			aspStateStr(scb->state)));
1443
1444		return;
1445	}
1446
1447	scb = (asp_scb_t *)gref->info;
1448	if (scb == 0) {
1449		gbuf_freem(mioc);
1450		return;
1451	}
1452
1453	if (iocbp->ioc_cmd == AT_ATP_REQUEST_COMPLETE) {
1454		if (scb->next_scb) {
1455			/*
1456			 * find the responsible scb
1457			 */
1458			scb = (asp_scb_t *)iocbp->ioc_private;
1459			if ((scb == 0) || (scb->magic_num != 222)) {
1460				dPrintf(D_M_ASP, D_L_ERROR,
1461					("asp_nak_reply: CAN'T find scb 1\n"));
1462				gbuf_freem(mioc);
1463				return;
1464			}
1465		}
1466		dPrintf(D_M_ASP, D_L_WARNING,
1467			("asp_nak_reply: RSP, loc=%d, rem=%x.%x.%d, state=%s\n",
1468			scb->loc_addr.socket,
1469			scb->rem_addr.net,
1470			scb->rem_addr.node,
1471			scb->rem_addr.socket,
1472			aspStateStr(scb->state)));
1473
1474		switch (scb->state) {
1475		case ASPSTATE_WaitingForGetStatusRsp:
1476			iocbp->ioc_cmd = ASPIOC_GetStatus;
1477			break;
1478
1479		case ASPSTATE_WaitingForOpenSessRsp:
1480			iocbp->ioc_cmd = ASPIOC_OpenSession;
1481			break;
1482
1483		case ASPSTATE_WaitingForCommandRsp:
1484		case ASPSTATE_WaitingForWriteRsp:
1485		case ASPSTATE_WaitingForWriteContinueRsp:
1486			scb->state = ASPSTATE_Idle;
1487
1488			/* last remaining use of MSG_ERROR */
1489			gbuf_set_type(mioc, MSG_ERROR);
1490			*gbuf_rptr(mioc) = (u_char)EPROTOTYPE;
1491			gbuf_wset(mioc, 1);
1492			if (gbuf_cont(mioc)) {
1493				gbuf_freem(gbuf_cont(mioc));
1494				gbuf_cont(mioc) = 0;
1495			}
1496
1497			asp_putnext(scb->gref, mioc);
1498			return;
1499
1500		case ASPSTATE_WaitingForCloseSessRsp:
1501			scb->state = ASPSTATE_Close;
1502			/* fall through */
1503		case ASPSTATE_Close: /* new for PR-2296832 */
1504			scb->rem_addr.node = 0;
1505			iocbp->ioc_cmd = ASPIOC_CloseSession;
1506			iocbp->ioc_rval = 0;
1507			if (gbuf_cont(mioc)) {
1508				gbuf_freem(gbuf_cont(mioc));
1509				gbuf_cont(mioc) = 0;
1510			}
1511			gbuf_set_type(mioc, MSG_IOCACK);
1512			atalk_putnext(scb->gref, mioc);
1513			return;
1514
1515		default:
1516			gbuf_freem(mioc);
1517			return;
1518		}
1519		scb->state = ASPSTATE_Idle;
1520		atalk_putnext(gref, mioc);
1521	}
1522
1523	else {
1524		if (scb->next_scb) {
1525			/*
1526			 * find the responsible scb
1527			 */
1528			scb = (asp_scb_t *)iocbp->ioc_cr;
1529			if ((scb == 0) || (scb->magic_num != 222)) {
1530				dPrintf(D_M_ASP, D_L_ERROR,
1531					("asp_nak_reply: CAN'T find scb 2\n"));
1532				gbuf_freem(mioc);
1533				return;
1534			}
1535		}
1536
1537		switch (scb->state) {
1538		case ASPSTATE_Close:
1539			scb->rem_addr.node = 0;
1540			break;
1541		}
1542
1543		gbuf_freem(mioc);
1544	}
1545} /* asp_nak_reply */
1546
1547/*
1548 * delete scb from the use list
1549 */
1550StaticProc void
1551asp_dequeue_scb(scb)
1552	asp_scb_t *scb;
1553{
1554
1555	if (scb == scb_used_list) {
1556		if ((scb_used_list = scb->next_scb) != 0)
1557			scb->next_scb->prev_scb = 0;
1558	} else {
1559		if ((scb->prev_scb->next_scb = scb->next_scb) != 0)
1560			scb->next_scb->prev_scb = scb->prev_scb;
1561	}
1562
1563	scb->next_scb = 0;
1564	scb->prev_scb = 0;
1565}
1566
1567/*
1568 * find scb routine
1569 */
1570StaticProc asp_scb_t *
1571asp_find_scb(sock_num, rem_addr)
1572	unsigned char sock_num;
1573	at_inet_t *rem_addr;
1574{
1575	asp_scb_t *scb;
1576	asp_scb_t *alt_scb = 0;
1577
1578	for (scb = asp_scbQ[sock_num]; scb; scb = scb->next_scb) {
1579		if ((scb->rem_addr.net == rem_addr->net)
1580			&& (scb->rem_addr.node == rem_addr->node)) {
1581			if ((scb->rem_addr.socket == rem_addr->socket)
1582					|| (scb->rem_socket == rem_addr->socket))
1583				break;
1584			else if (alt_scb == 0)
1585				alt_scb = scb;
1586		}
1587	}
1588
1589	if ((scb == 0) && ((scb = alt_scb) == 0)) {
1590		dPrintf(D_M_ASP, D_L_ERROR,
1591			("asp_find_scb: CAN'T find scb, loc=%d, rem=%x.%x.%d\n",
1592			sock_num,
1593			rem_addr->net,
1594			rem_addr->node,
1595			rem_addr->socket));
1596	}
1597
1598	return scb;
1599}
1600
1601/*
1602 * timout routine
1603 */
1604StaticProc void
1605asp_timout(func, scb, seconds)
1606	asp_tmo_func func;
1607	register asp_scb_t *scb;
1608	int seconds;
1609{
1610	unsigned char sum;
1611	register asp_scb_t *curr_scb, *prev_scb;
1612
1613	if (scb->tmo_func)
1614		return;
1615
1616	scb->tmo_func = func;
1617	scb->tmo_delta = (seconds>>SESS_TMO_RES);
1618	scb->tmo_cnt = scb_tmo_cnt;
1619
1620	if (scb_tmo_list == 0) {
1621		scb->next_tmo = scb->prev_tmo = 0;
1622		scb_tmo_list = scb;
1623		return;
1624	}
1625
1626	prev_scb = 0;
1627	curr_scb = scb_tmo_list;
1628	sum = 0;
1629
1630	while (1) {
1631		sum += curr_scb->tmo_delta;
1632		if (sum > scb->tmo_delta) {
1633			sum -= curr_scb->tmo_delta;
1634			scb->tmo_delta -= sum;
1635			curr_scb->tmo_delta -= scb->tmo_delta;
1636			break;
1637		}
1638		prev_scb = curr_scb;
1639		if ((curr_scb = curr_scb->next_tmo) == 0) {
1640			scb->tmo_delta -= sum;
1641			break;
1642		}
1643	}
1644
1645	if (prev_scb) {
1646		scb->prev_tmo = prev_scb;
1647		if ((scb->next_tmo = prev_scb->next_tmo) != 0)
1648			prev_scb->next_tmo->prev_tmo = scb;
1649		prev_scb->next_tmo = scb;
1650	} else {
1651		scb->prev_tmo = 0;
1652		scb->next_tmo = scb_tmo_list;
1653		scb_tmo_list->prev_tmo = scb;
1654		scb_tmo_list = scb;
1655	}
1656}
1657
1658/*
1659 * untimout routine
1660 */
1661StaticProc void
1662asp_untimout(
1663	__unused asp_tmo_func tmo_func,
1664	register asp_scb_t *scb)
1665{
1666
1667	if ((scb->tmo_cnt == scb_tmo_cnt) || (scb->tmo_func == 0))
1668		return;
1669
1670	if (scb_tmo_list == scb) {
1671		if ((scb_tmo_list = scb->next_tmo) != 0) {
1672			scb_tmo_list->prev_tmo = 0;
1673			scb->next_tmo->tmo_delta += scb->tmo_delta;
1674		}
1675	} else if (scb->prev_tmo) {
1676		if ((scb->prev_tmo->next_tmo = scb->next_tmo) != 0) {
1677			scb->next_tmo->prev_tmo = scb->prev_tmo;
1678			scb->next_tmo->tmo_delta += scb->tmo_delta;
1679		}
1680		scb->prev_tmo = 0;
1681	}
1682	scb->tmo_func = 0;
1683}
1684
1685/*
1686 * hangup routine
1687 */
1688StaticProc void
1689asp_hangup(scb)
1690	asp_scb_t *scb;
1691{
1692	/*
1693	 * set the state to Close
1694	 */
1695	scb->state = ASPSTATE_Close;
1696	if (scb->tickle_tid) {
1697		atp_cancel_req(scb->gref, (unsigned int)scb->tickle_tid);
1698		scb->tickle_tid = 0;
1699	}
1700
1701	/*
1702	 * notify upstream of the hangup
1703	 */
1704	if (scb->rem_addr.node) {
1705		if (scb->get_wait)
1706			wakeup(&scb->event);
1707		else
1708			atalk_notify_sel(scb->gref);
1709	}
1710}
1711
1712StaticProc void
1713asp_iocack(gref, mioc)
1714	gref_t *gref;
1715	gbuf_t *mioc;
1716{
1717	if (gbuf_cont(mioc))
1718		((ioc_t *)gbuf_rptr(mioc))->ioc_count = gbuf_msgsize(gbuf_cont(mioc));
1719	else
1720		((ioc_t *)gbuf_rptr(mioc))->ioc_count = 0;
1721
1722	gbuf_set_type(mioc, MSG_IOCACK);
1723	atalk_putnext(gref, mioc);
1724}
1725
1726StaticProc void
1727asp_iocnak(gref, mioc, err)
1728	gref_t *gref;
1729	gbuf_t *mioc;
1730	int err;
1731{
1732	((ioc_t *)gbuf_rptr(mioc))->ioc_count = 0;
1733	if (err == 0)
1734		err = ENXIO;
1735	((ioc_t *)gbuf_rptr(mioc))->ioc_error = err;
1736	((ioc_t *)gbuf_rptr(mioc))->ioc_rval = -1;
1737	if (gbuf_cont(mioc)) {
1738		gbuf_freem(gbuf_cont(mioc));
1739		gbuf_cont(mioc) = 0;
1740	}
1741
1742	gbuf_set_type(mioc, MSG_IOCNAK);
1743	atalk_putnext(gref, mioc);
1744}
1745
1746/*
1747 * the alloc scb routine
1748 */
1749StaticProc asp_scb_t *
1750asp_scb_alloc()
1751{
1752	int i;
1753	gbuf_t *m;
1754	asp_scb_t *scb, *scb_array;
1755
1756	if (scb_free_list == 0) {
1757		if ((m = gbuf_alloc(SCBS_PER_BLK*sizeof(asp_scb_t), PRI_MED)) == 0)
1758			return (asp_scb_t *)0;
1759		bzero((char *)gbuf_rptr(m), SCBS_PER_BLK*sizeof(asp_scb_t));
1760		gbuf_cont(m) = scb_resource_m;
1761		scb_resource_m = m;
1762		scb_array = (asp_scb_t *)gbuf_rptr(m);
1763		for (i=0; i < SCBS_PER_BLK-1; i++)
1764			scb_array[i].next_scb = (asp_scb_t *)&scb_array[i+1];
1765		scb_array[i].next_scb = 0;
1766		scb_free_list = (asp_scb_t *)&scb_array[0];
1767	}
1768
1769	scb = scb_free_list;
1770	scb_free_list = scb->next_scb;
1771	ATEVENTINIT(scb->event);
1772	ATEVENTINIT(scb->delay_event);
1773
1774	return scb;
1775}
1776
1777/*
1778 * the free scb routine
1779 */
1780StaticProc void
1781asp_scb_free(scb)
1782	asp_scb_t *scb;
1783{
1784
1785	bzero((char *)scb, sizeof(asp_scb_t));
1786	scb->next_scb = scb_free_list;
1787	scb_free_list = scb;
1788}
1789
1790/*
1791 * routine to pass up receive data
1792 */
1793StaticProc void
1794asp_putnext(gref, mproto)
1795	gref_t *gref;
1796	gbuf_t *mproto;
1797{
1798	gbuf_t *m;
1799	asp_scb_t *scb;
1800
1801	scb = (asp_scb_t *)gref->info;
1802
1803	/*
1804	 * queue the message.
1805	 */
1806	gbuf_next(mproto) = 0;
1807	if ((m = scb->sess_ioc) == 0)
1808		scb->sess_ioc = mproto;
1809	else {
1810		while (gbuf_next(m))
1811			m = gbuf_next(m);
1812		gbuf_next(m) = mproto;
1813	}
1814	scb->rcv_cnt++;
1815	if (scb->rcv_cnt >= MAX_RCV_CNT)
1816		scb->snd_stop = 1;
1817
1818	if (scb->get_wait)
1819		wakeup(&scb->event);
1820	else if (mproto == scb->sess_ioc)
1821		atalk_notify_sel(gref);
1822
1823} /* asp_putnext */
1824
1825/*
1826 * The following two routines are direct entries from system
1827 * calls to allow fast sending and recving of ASP data.
1828 */
1829
1830/* in ASPputmsg we expect:
1831
1832    ASPFUNC_CmdReply
1833    ASPFUNC_Attention
1834    ASPFUNC_Command
1835    ASPFUNC_Write
1836    ASPFUNC_WriteContinue
1837
1838    bms:  Make this callable from the kernel.
1839    If mreq != NULL, then must be called from kernel space and the following apply:
1840    1)  *mreq is data to be sent already in mbuf chains.
1841    2)  datptr->len = size of data
1842*/
1843
1844int ASPputmsg(gref_t *gref, strbuf_t *ctlptr, strbuf_t *datptr, gbuf_t *mreq, __unused int flags, int *errp)
1845{
1846    int i, err, len, offset, remain, size, copy_len;
1847    gbuf_t *mioc, *mdata, *mx;
1848    ioc_t *iocbp;
1849    strbuf_t ctlbuf;
1850    strbuf_t datbuf;
1851    asp_scb_t *scb;
1852    int nbds, result, msize, Primitive;
1853    unsigned char *wptr;
1854    struct atp_set_default *sd;
1855    at_ddp_t *ddp;
1856    at_atp_t *atp;
1857    struct atpBDS *atpBDS;
1858    asp_word_t *awp;
1859    union asp_primitives *primitives;
1860    unsigned short tid;
1861    caddr_t		dataptr;
1862
1863    if ((scb = (asp_scb_t *)gref->info) == 0) {
1864		dPrintf(D_M_ASP, D_L_ERROR,
1865			("ASPputmsg: stale handle=0x%x, pid=%d\n",
1866			(u_int) gref, gref->pid));
1867
1868        *errp = EINVAL;
1869        return -1;
1870    }
1871
1872    if (scb->state == ASPSTATE_Close)
1873        return 0;
1874    if (scb->snd_stop) {
1875        *errp = EAGAIN;
1876        return -1;
1877    }
1878
1879    /*
1880     * copy in the control and data info
1881     */
1882     if (mreq != NULL) {
1883        /* being called from kernel space */
1884        bcopy (ctlptr, &ctlbuf, sizeof (strbuf_t));
1885        bcopy (datptr, &datbuf, sizeof (strbuf_t));
1886     } else {
1887        /* being called from user space */
1888        if ((err = copyin(CAST_USER_ADDR_T(ctlptr), (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0)
1889            goto l_err;
1890        if ((err = copyin(CAST_USER_ADDR_T(datptr), (caddr_t)&datbuf, sizeof(datbuf))) != 0)
1891            goto l_err;
1892     }
1893
1894     /* Radar 5398072: check for bogus length
1895      * 	       Max ASP data is 8 ATP packets
1896      */
1897
1898     if ((ctlbuf.len < 0) || (ctlbuf.len > (ATP_DATA_SIZE * 8))) {
1899	     err = EINVAL;
1900	     goto l_err;
1901     }
1902     if ((datbuf.len < 0) || (datbuf.len > (ATP_DATA_SIZE * 8))) {
1903	     err = EINVAL;
1904	     goto l_err;
1905     }
1906
1907    /*
1908     * allocate buffer and copy in the control content
1909     */
1910    if (!(mioc = gbuf_alloc_wait(ctlbuf.len, TRUE))) {
1911        /* error return should not be possible */
1912        err = ENOBUFS;
1913        goto l_err;
1914    }
1915    gbuf_set_type(mioc, MSG_IOCTL); /* for later, in ATP */
1916    gbuf_wset(mioc, ctlbuf.len);
1917
1918    if (mreq != NULL) {
1919        /* being called from kernel space */
1920        bcopy (ctlbuf.buf, gbuf_rptr(mioc), ctlbuf.len);
1921    } else {
1922        /* being called from user space */
1923        if ((err = copyin(CAST_USER_ADDR_T(ctlbuf.buf), (caddr_t)gbuf_rptr(mioc), ctlbuf.len)) != 0) {
1924            gbuf_freem(mioc);
1925            goto l_err;
1926        }
1927    }
1928
1929    iocbp = (ioc_t *)gbuf_rptr(mioc);
1930    primitives = (union asp_primitives *)gbuf_rptr(mioc);
1931    Primitive = primitives->Primitive;
1932	dPrintf(D_M_ASP, D_L_INFO,
1933		("ASPputmsg: %s\n", aspCmdStr(Primitive)));
1934
1935    /*
1936     * copy in the data content into multiple mbuf clusters if
1937     * required.  ATP now expects reply data to be placed in
1938     * standard clusters, not the large external clusters that
1939     * were used previously.
1940     */
1941
1942    /* set offset for use by some commands */
1943    offset = (Primitive == ASPFUNC_CmdReply) ? 0 : aspCMDsize;
1944	size = 0;
1945    if (mreq != NULL) {
1946        /* The data from the in-kernel call for use by AFP is passed
1947         * in as one large external cluster.  This needs to be copied
1948         * to a chain of standard clusters.
1949         */
1950        remain = gbuf_len(mreq);
1951        dataptr = mtod(mreq, caddr_t);
1952    } else {
1953    	/* copyin from user space */
1954    	remain = datbuf.len;
1955    	dataptr = (caddr_t)datbuf.buf;
1956    }
1957
1958    /* allocate first buffer */
1959    if (!(mdata = gbuf_alloc_wait((remain + offset > MCLBYTES ? MCLBYTES : remain + offset), TRUE))) {
1960        /* error return should not be possible */
1961        err = ENOBUFS;
1962        gbuf_freem(mioc);
1963        goto l_err;
1964    }
1965    gbuf_wset(mdata, 0);		/* init length to zero */
1966    gbuf_cont(mioc) = mdata;
1967
1968	while (remain) {
1969		if (remain + offset > MCLBYTES)
1970			copy_len = MCLBYTES - offset;
1971		else
1972			copy_len = remain;
1973		remain -= copy_len;
1974		if (mreq != NULL)
1975			bcopy (dataptr, (gbuf_rptr(mdata) + offset), copy_len);
1976		else if ((err = copyin(CAST_USER_ADDR_T(dataptr), (caddr_t)(gbuf_rptr(mdata) + offset), copy_len)) != 0) {
1977			gbuf_freem(mioc);
1978			goto l_err;
1979		}
1980		gbuf_wset(mdata, (copy_len + offset));
1981		size += copy_len + offset;
1982		dataptr += copy_len;
1983		offset = 0;
1984		if (remain) {
1985			/* allocate the next mbuf */
1986			if ((gbuf_cont(mdata) = m_get((M_WAIT), MSG_DATA)) == 0) {
1987				err = ENOBUFS;
1988				gbuf_freem(mioc);
1989				goto l_err;
1990			}
1991			mdata = gbuf_cont(mdata);
1992			MCLGET(mdata, M_WAIT);
1993			if (!(mdata->m_flags & M_EXT)) {
1994				err = ENOBUFS;
1995				gbuf_freem(mioc);
1996				goto l_err;
1997			}
1998		}
1999	}
2000	mdata = gbuf_cont(mioc);			/* code further on down expects this to b e set */
2001	mdata->m_pkthdr.len = size;			/* set packet hdr len */
2002
2003	if (mreq != 0)
2004		gbuf_freem(mreq);
2005
2006   	switch (Primitive) {
2007
2008    case ASPFUNC_Command:
2009    case ASPFUNC_Write:
2010    case ASPFUNC_WriteContinue:
2011    case ASPFUNC_Attention:
2012        /*
2013         * build the command/write/write_continue request
2014         */
2015        wptr = (unsigned char *)gbuf_rptr(mdata);
2016        atpBDS = (struct atpBDS *)wptr;
2017        wptr += atpBDSsize;
2018        for (i=0; i < ATP_TRESP_MAX; i++) {
2019            *(unsigned long  *)atpBDS[i].bdsBuffAddr = 1;
2020            *(unsigned short *)atpBDS[i].bdsBuffSz = ATP_DATA_SIZE;
2021        }
2022        sd = (struct atp_set_default *)wptr;
2023        wptr += sizeof(struct atp_set_default);
2024        sd->def_retries = (scb->cmd_retry.retries == -1) ?
2025          ATP_INFINITE_RETRIES : scb->cmd_retry.retries;
2026        sd->def_rate = scb->cmd_retry.interval*TICKS_PER_SEC;
2027        sd->def_BDSlen = atpBDSsize;
2028        ddp = (at_ddp_t *)wptr;
2029        NET_ASSIGN(ddp->src_net, scb->loc_addr.net);
2030        ddp->src_node = scb->loc_addr.node;
2031        NET_ASSIGN(ddp->dst_net, scb->rem_addr.net);
2032        ddp->dst_node = scb->rem_addr.node;
2033        ddp->dst_socket = scb->rem_addr.socket;
2034        UAS_ASSIGN(ddp->checksum, 0);
2035        atp = ATP_ATP_HDR(wptr);
2036        wptr += TOTAL_ATP_HDR_SIZE;
2037        atp->xo = 1;
2038        atp->xo_relt = 1;
2039        atp->bitmap = 0xff;
2040        awp = (asp_word_t *)atp->user_bytes;
2041        awp->func = (unsigned char)Primitive;
2042        awp->param1 = scb->sess_id;
2043        awp->param2 = htons(scb->snd_seq_num);
2044        iocbp->ioc_private = (void *)scb;
2045        iocbp->ioc_count = gbuf_len(mdata);
2046        iocbp->ioc_rval = 0;
2047        iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF;
2048
2049        /*
2050         * send the command/write/write_continue/attention request
2051         */
2052        switch (awp->func) {
2053        case ASPFUNC_Command:
2054            scb->state = ASPSTATE_WaitingForCommandRsp;
2055            break;
2056        case ASPFUNC_Write:
2057            scb->state = ASPSTATE_WaitingForWriteRsp;
2058            break;
2059        case ASPFUNC_WriteContinue:
2060            scb->state = ASPSTATE_WaitingForWriteContinueRsp;
2061            awp->param2 = htons(scb->wrt_seq_num);
2062            break;
2063        case ASPFUNC_Attention:
2064            scb->state = ASPSTATE_WaitingForCommandRsp;
2065            atp->xo = 0;
2066            atp->xo_relt = 0;
2067            atp->bitmap = 0x01;
2068            gbuf_wdec(mdata,2);
2069            awp->param2 = htons(*(unsigned short *)gbuf_wptr(mdata));
2070            break;
2071        }
2072        dPrintf(D_M_ASP,D_L_INFO,
2073            ("ASPputmsg: %s, loc=%d, rem=%x.%x.%d\n",
2074             (awp->func == ASPFUNC_Command ? "CommandReq" :
2075              awp->func == ASPFUNC_Write ? "WriteReq" :
2076              awp->func == ASPFUNC_WriteContinue ? "WriteContinue" :
2077              "AttentionReq"),scb->loc_addr.socket,
2078             NET_VALUE(ddp->dst_net),ddp->dst_node,ddp->dst_socket));
2079        atp_send_req(gref, mioc);
2080        return 0;
2081
2082    case ASPFUNC_CmdReply:
2083
2084        if (scb->req_msgq) {
2085            mx = scb->req_msgq;
2086            scb->req_msgq = gbuf_next(mx);
2087            gbuf_next(mx) = 0;
2088            asp_putnext(scb->gref, mx);
2089        } else
2090            scb->req_flag = 0;
2091
2092        result = primitives->CmdReplyReq.CmdResult;
2093        tid = primitives->CmdReplyReq.ReqRefNum;
2094
2095        /* Re-use the original mioc mbuf to send the response. */
2096        gbuf_rinc(mioc,sizeof(void *));
2097        gbuf_wset(mioc,0);
2098        ddp = (at_ddp_t *)gbuf_wptr(mioc);
2099        gbuf_winc(mioc,DDP_X_HDR_SIZE);
2100        atp = (at_atp_t *)gbuf_wptr(mioc);
2101        gbuf_winc(mioc,ATP_HDR_SIZE);
2102        NET_ASSIGN(ddp->src_net, scb->loc_addr.net);
2103        ddp->src_node = scb->loc_addr.node;
2104        NET_ASSIGN(ddp->dst_net, scb->rem_addr.net);
2105        ddp->dst_node = scb->rem_addr.node;
2106        ddp->dst_socket = scb->reply_socket;
2107        ddp->type = DDP_ATP;
2108        UAS_ASSIGN(ddp->checksum, 0);
2109        UAS_ASSIGN(atp->tid, htons(tid));
2110        if (scb->attn_flag && (tid == scb->attn_tid)) {
2111           scb->attn_flag = 0;
2112            atp->xo = 0;
2113            atp->xo_relt = 0;
2114        } else {
2115            atp->xo = 1;
2116            atp->xo_relt = 1;
2117        }
2118        /* setup the atpBDS struct - only the length field is used,
2119         * except for the first one which contains the bds count in
2120         * bdsDataSz.
2121         */
2122        atpBDS = (struct atpBDS *)gbuf_wptr(mioc);
2123        msize = mdata ? gbuf_msgsize(mdata) : 0;
2124       	for (nbds=0; (nbds < ATP_TRESP_MAX) && (msize > 0); nbds++) {
2125            len = msize < ATP_DATA_SIZE ? msize : ATP_DATA_SIZE;
2126            msize -= ATP_DATA_SIZE;
2127            *(long *)atpBDS[nbds].bdsUserData = 0;
2128            UAL_ASSIGN(atpBDS[nbds].bdsBuffAddr, 1);
2129            UAS_ASSIGN(atpBDS[nbds].bdsBuffSz, len);
2130        }
2131       	UAS_ASSIGN(atpBDS[0].bdsDataSz, nbds);
2132        *(long *)atpBDS[0].bdsUserData = (long)result;
2133        *(long *)atp->user_bytes = (long)result;
2134        gbuf_winc(mioc,atpBDSsize);
2135		dPrintf(D_M_ASP, D_L_INFO,
2136			("ASPputmsg: ATP CmdReplyReq, loc=%d, state=%s, msgsize = %d, result = %d, tid = %d\n",
2137			 scb->loc_addr.socket, aspStateStr(scb->state),
2138			 (mdata ? gbuf_msgsize(mdata) : 0), result, tid));
2139        atp_send_rsp(gref, mioc, TRUE);
2140        return 0;
2141    }
2142
2143    /* Not an expected ASPFUNC */
2144    gbuf_freem(mioc);
2145    err = EOPNOTSUPP;
2146
2147l_err:
2148    *errp = err;
2149    return -1;
2150} /* ASPputmsg */
2151
2152
2153/* bms:  make this callable from kernel.  reply date is passed back as a mbuf chain in *mreply  */
2154int ASPgetmsg(gref_t *gref, strbuf_t *ctlptr, strbuf_t *datptr, gbuf_t **mreply, __unused int *flags, int *errp)
2155{
2156    int err, len, sum, rval;
2157    gbuf_t *mproto, *mdata;
2158    strbuf_t ctlbuf;
2159    strbuf_t datbuf;
2160    asp_scb_t *scb;
2161    unsigned char get_wait;
2162
2163    if ((scb = (asp_scb_t *)gref->info) == 0) {
2164		dPrintf(D_M_ASP, D_L_ERROR,
2165			("ASPgetmsg: stale handle=0x%x, pid=%d\n",
2166			(u_int) gref, gref->pid));
2167
2168		*errp = EINVAL;
2169		return -1;
2170	}
2171
2172    if (scb->state == ASPSTATE_Close)
2173        return 0;
2174
2175    /*
2176     * get receive data
2177     */
2178    while ((mproto = scb->sess_ioc) == 0) {
2179        scb->get_wait = 1;
2180	   lck_mtx_assert(atalk_mutex, LCK_MTX_ASSERT_OWNED);
2181        err = msleep(&scb->event, atalk_mutex, PSOCK | PCATCH, "aspgetmsg", 0);
2182        if (err != 0) {
2183            scb->get_wait = 0;
2184            *errp = err;
2185            return -1;
2186        }
2187        if (scb->state == ASPSTATE_Close) {
2188            scb->get_wait = 0;
2189            return 0;
2190        }
2191    }
2192    get_wait = scb->get_wait;
2193    scb->get_wait = 0;
2194    if ((ctlptr == 0) && (datptr == 0))
2195        return 0;
2196    scb->sess_ioc = gbuf_next(mproto);
2197    mdata = gbuf_cont(mproto);
2198
2199    /* last remaining use of MSG_ERROR */
2200    if (gbuf_type(mproto) == MSG_ERROR) {
2201        err = (int)gbuf_rptr(mproto)[0];
2202        goto l_err;
2203    }
2204
2205    /*
2206     * copy in the control and data info
2207     */
2208    if (mreply != NULL) {
2209        /* called from kernel space */
2210        bcopy (ctlptr, &ctlbuf, sizeof(ctlbuf));
2211        bcopy (datptr, &datbuf, sizeof(datbuf));
2212    } else {
2213        /* called from user space */
2214        if ((err = copyin(CAST_USER_ADDR_T(ctlptr),
2215                (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0)
2216            goto l_err;
2217        if ((err = copyin(CAST_USER_ADDR_T(datptr),
2218                (caddr_t)&datbuf, sizeof(datbuf))) != 0)
2219            goto l_err;
2220    }
2221    if ((datbuf.maxlen < 0) || (datbuf.maxlen < gbuf_msgsize(mdata))) {
2222        gbuf_next(mproto) = scb->sess_ioc;
2223        scb->sess_ioc = mproto;
2224        return MOREDATA;
2225    }
2226
2227    if (get_wait == 0) {
2228        /*
2229         * this is a hack to support the select() call.
2230         * we're not supposed to dequeue messages in the Streams
2231         * head's read queue this way; but there is no better way.
2232         */
2233        if (scb->sess_ioc != 0)
2234            atalk_notify_sel(gref);
2235
2236    }
2237
2238    /*
2239     * copy out the control content and info
2240     */
2241    ctlbuf.len = gbuf_len(mproto);
2242
2243    if (mreply != NULL) {
2244        /* called from kernel space */
2245        bcopy (gbuf_rptr(mproto), ctlbuf.buf, ctlbuf.len);
2246        bcopy (&ctlbuf, ctlptr, sizeof(ctlbuf));
2247    } else {
2248        /* called from user space */
2249        if ((err = copyout((caddr_t)gbuf_rptr(mproto),
2250                CAST_USER_ADDR_T(ctlbuf.buf), ctlbuf.len)) != 0)
2251            goto l_err;
2252        if ((err = copyout((caddr_t)&ctlbuf,
2253                CAST_USER_ADDR_T(ctlptr), sizeof(ctlbuf))) != 0)
2254            goto l_err;
2255    }
2256
2257    /*
2258     * copy out the data content and info
2259     */
2260    for (rval = 0, sum = 0; mdata && (rval == 0); mdata = gbuf_cont(mdata))
2261    {
2262        len = gbuf_len(mdata);
2263        if (len) {
2264            if ((len + sum) > datbuf.maxlen) {
2265                len = datbuf.maxlen - sum;
2266                rval = MOREDATA;
2267            }
2268
2269            if (mreply == NULL) {
2270                /* called from user space */
2271                if ((err = copyout((caddr_t)gbuf_rptr(mdata), CAST_USER_ADDR_T(&datbuf.buf[sum]), len)) != 0)
2272                    goto l_err;
2273            }
2274            sum += len;
2275        }
2276    }
2277    datbuf.len = sum;
2278    if (mreply != NULL) {
2279        /* called from kernel space */
2280        bcopy (&datbuf, datptr, sizeof(datbuf));
2281    } else {
2282        /* called from user space */
2283        if ((err = copyout((caddr_t)&datbuf, CAST_USER_ADDR_T(datptr), sizeof(datbuf))) != 0)
2284            goto l_err;
2285    }
2286
2287    if (mreply != NULL) {
2288        /* called from kernel space */
2289        /* return the reply data in mbufs, so dont free them.
2290        Just free the proto info */
2291        mdata = gbuf_cont(mproto);
2292        *mreply = mdata;
2293        gbuf_cont(mproto) = NULL;
2294        gbuf_freem(mproto);
2295    } else {
2296        /* called from user space */
2297        gbuf_freem(mproto);
2298    }
2299
2300    if (scb->sess_ioc)
2301        scb->rcv_cnt--;
2302    else {
2303        scb->rcv_cnt = 0;
2304        scb->snd_stop = 0;
2305    }
2306    return rval;
2307
2308l_err:
2309    gbuf_next(mproto) = scb->sess_ioc;
2310    scb->sess_ioc = mproto;
2311    *errp = err;
2312    return -1;
2313}
2314