1/*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 *	Copyright (c) 1995 Apple Computer, Inc.
30 *
31 *  Change Log:
32 *    Created, 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/file_internal.h>
45#include <sys/mbuf.h>
46#include <sys/ioctl.h>
47#include <sys/malloc.h>
48#include <kern/locks.h>
49#include <sys/socket.h>
50#include <sys/socketvar.h>
51#include <sys/ioccom.h>
52#include <sys/uio_internal.h>
53#include <sys/file.h>
54#include <sys/vnode.h>
55
56#include <sys/sysctl.h>
57
58#include <net/if.h>
59
60#include <netat/sysglue.h>
61#include <netat/appletalk.h>
62#include <netat/ddp.h>
63#include <netat/at_pcb.h>
64#include <netat/at_var.h>
65#include <netat/routing_tables.h>
66#include <netat/adsp.h>
67#include <netat/adsp_internal.h>
68#include <netat/asp.h>
69#include <netat/atp.h>
70#include <netat/debug.h>
71
72int _ATkqfilter(struct fileproc *, struct knote *, vfs_context_t);
73int _ATselect(struct fileproc *, int, void *, vfs_context_t);
74int _ATioctl(struct fileproc *, u_long, caddr_t, vfs_context_t);
75int _ATwrite(struct fileproc *, struct uio *, int, vfs_context_t);
76int _ATread(struct fileproc *, struct uio *, int, vfs_context_t);
77int _ATclose(struct fileglob *, vfs_context_t);
78
79int _ATrw(struct fileproc *, enum uio_rw, struct uio *, vfs_context_t);
80
81extern struct atpcb ddp_head;
82extern lck_mtx_t * atalk_mutex;
83
84int atp_free_cluster_timeout_set = 0;
85
86int gref_alloc(gref_t **);
87
88
89/* bms:  make gref_close non static so its callable from kernel */
90int gref_close(gref_t *gref);
91
92SYSCTL_DECL(_net_appletalk);
93dbgBits_t dbgBits;
94SYSCTL_STRUCT(_net_appletalk, OID_AUTO, debug, CTLFLAG_WR,
95	      &dbgBits, dbgBits, "AppleTalk Debug Flags");
96int RouterMix = RT_MIX_DEFAULT; /* default for nbr of ppsec */
97SYSCTL_INT(_net_appletalk, OID_AUTO, routermix, CTLFLAG_WR,
98			&RouterMix, 0, "Appletalk RouterMix");
99at_ddp_stats_t at_ddp_stats;		/* DDP statistics */
100SYSCTL_STRUCT(_net_appletalk, OID_AUTO, ddpstats, CTLFLAG_RD | CTLFLAG_LOCKED,
101	      &at_ddp_stats, at_ddp_stats, "AppleTalk DDP Stats");
102extern int atp_resp_seqno2big;
103SYSCTL_INT(_net_appletalk, OID_AUTO, atp_resp_seqno2big, CTLFLAG_RD | CTLFLAG_LOCKED,
104                        &atp_resp_seqno2big, 0, "Appletalk ATP seqno too big count");
105
106static void ioccmd_t_32_to_64( ioccmd_t *from_p, user_ioccmd_t *to_p );
107static void ioccmd_t_64_to_32( user_ioccmd_t *from_p, ioccmd_t *to_p );
108
109extern lck_mtx_t *atalk_cluster_lock;
110caddr_t	atp_free_cluster_list = NULL;
111
112void gref_wput(gref_t *, gbuf_t *m);
113
114void gref_wput(gref, m)
115	gref_t *gref;
116	gbuf_t *m;
117{
118	switch (gref->proto) {
119	case ATPROTO_DDP:
120		ddp_putmsg(gref, m); break;
121	case ATPROTO_LAP:
122		elap_wput(gref, m); break;
123	case ATPROTO_ATP:
124		atp_wput(gref, m); break;
125	case ATPROTO_ASP:
126		asp_wput(gref, m); break;
127#ifdef AURP_SUPPORT
128	case ATPROTO_AURP:
129		aurp_wput(gref, m); break;
130#endif
131	case ATPROTO_ADSP:
132		adsp_wput(gref, m); break;
133	case ATPROTO_NONE:
134		if (gbuf_type(m) == MSG_IOCTL) {
135			gbuf_freem(gbuf_cont(m));
136			gbuf_cont(m) = 0;
137			((ioc_t *)gbuf_rptr(m))->ioc_rval = -1;
138			((ioc_t *)gbuf_rptr(m))->ioc_error = EPROTOTYPE;
139			gbuf_set_type(m, MSG_IOCNAK);
140			atalk_putnext(gref, m);
141		} else
142			gbuf_freem(m);
143		break;
144	default:
145		gbuf_freem(m);
146		break;
147	}
148}
149
150int _ATsocket(proto, err, proc)
151	int proto;
152	int *err;
153	void *proc;
154{
155	int fd;
156	gref_t *gref;
157
158	/* make sure the specified protocol id is valid */
159	switch (proto) {
160
161	/* ATPROTO_DDP and ATPROTO_LAP have been replaced with
162	   BSD-style socket interface. */
163
164	case ATPROTO_ATP:
165	case ATPROTO_ASP:
166#ifdef AURP_SUPPORT
167	case ATPROTO_AURP:
168#endif
169	case ATPROTO_ADSP:
170		break;
171	default:
172		*err = EPROTOTYPE;
173#ifdef APPLETALK_DEBUG
174		kprintf("_ATsocket: error EPROTOTYPE =%d\n", *err);
175#endif
176		return -1;
177	}
178
179	/* allocate a protocol channel */
180	if ((*err = gref_alloc(&gref)) != 0) {
181#ifdef APPLETALK_DEBUG
182		kprintf("_ATsocket: error gref_open =%d\n", *err);
183#endif
184		return -1;
185	}
186	gref->proto = proto;
187	gref->pid = proc_pid((struct proc *)proc);
188
189	/* open the specified protocol */
190	switch (gref->proto) {
191
192	/* ATPROTO_DDP and ATPROTO_LAP have been replaced with
193	   BSD-style socket interface. */
194
195	case ATPROTO_ATP:
196		*err = atp_open(gref, 1); break;
197	case ATPROTO_ASP:
198		*err = asp_open(gref); break;
199#ifdef AURP_SUPPORT
200	case ATPROTO_AURP:
201		*err = aurp_open(gref); break;
202#endif
203	case ATPROTO_ADSP:
204		*err = adsp_open(gref); break;
205	}
206
207	/* create the descriptor for the channel */
208	if (*err) {
209#ifdef APPLETALK_DEBUG
210		kprintf("_ATsocket: open failed for %d proto; err = %d\n",
211			gref->proto, *err);
212#endif
213		gref->proto = ATPROTO_NONE;
214	}
215	if (*err || (*err = atalk_openref(gref, &fd, proc))) {
216#ifdef APPLETALK_DEBUG
217		kprintf("_ATsocket: error atalk_openref =%d\n", *err);
218#endif
219		(void)gref_close(gref);
220		return -1;
221	}
222/*
223	kprintf("_ATsocket: proto=%d return=%d fd=%d\n", proto, *err, fd);
224*/
225	return fd;
226} /* _ATsocket */
227
228int _ATgetmsg(fd, ctlptr, datptr, flags, err, proc)
229	int fd;
230	strbuf_t *ctlptr;
231	strbuf_t *datptr;
232	int *flags;
233	int *err;
234	void *proc;
235{
236	int rc = -1;
237	gref_t *gref;
238
239	if ((*err = atalk_getref(0, fd, &gref, proc, 1)) == 0) {
240		switch (gref->proto) {
241		case ATPROTO_ASP:
242			rc = ASPgetmsg(gref, ctlptr, datptr, NULL, flags, err);
243			break;
244		case ATPROTO_AURP:
245#ifdef AURP_SUPPORT
246			rc = AURPgetmsg(err);
247			break;
248#endif
249		default:
250			*err = EPROTONOSUPPORT;
251			break;
252		}
253		file_drop(fd);
254	}
255
256/*	kprintf("_ATgetmsg: return=%d\n", *err);*/
257	return rc;
258}
259
260int _ATputmsg(fd, ctlptr, datptr, flags, err, proc)
261	int fd;
262	strbuf_t *ctlptr;
263	strbuf_t *datptr;
264	int flags;
265	int *err;
266	void *proc;
267{
268	int rc = -1;
269	gref_t *gref;
270
271	if ((*err = atalk_getref(0, fd, &gref, proc, 1)) == 0) {
272		switch (gref->proto) {
273		case ATPROTO_ASP:
274			rc = ASPputmsg(gref, ctlptr, datptr, NULL, flags, err); break;
275		default:
276			*err = EPROTONOSUPPORT; break;
277		}
278		file_drop(fd);
279	}
280
281/*	kprintf("_ATputmsg: return=%d\n", *err); */
282	return rc;
283}
284
285int _ATclose(
286	struct fileglob *fg,
287	__unused vfs_context_t ctx)
288{
289	int err;
290	gref_t *gref;
291
292	if ((err = atalk_closeref(fg, &gref)) == 0) {
293		atalk_lock();
294	     (void)gref_close(gref);
295		atalk_unlock();
296	}
297
298	return err;
299}
300
301int _ATrw(fp, rw, uio, ctx)
302     struct fileproc *fp;
303     enum uio_rw rw;
304     struct uio *uio;
305	 vfs_context_t ctx;
306{
307    int err, len, clen = 0, res;
308    gref_t *gref;
309    gbuf_t *m, *mhead, *mprev;
310	proc_t p = vfs_context_proc(ctx);
311
312	/* no need to get/drop iocount as the fp already has one */
313    if ((err = atalk_getref_locked(fp, 0, &gref, p, 1)) != 0)
314    	return err;
315
316	// LP64todo - fix this!
317    if ((len = uio_resid(uio)) == 0)
318    	return 0;
319
320
321    if (rw == UIO_READ) {
322	KERNEL_DEBUG(DBG_ADSP_ATRW, 0, gref, len, gref->rdhead, 0);
323	while ((gref->errno == 0) && ((mhead = gref->rdhead) == 0)) {
324		gref->sevents |= POLLMSG;
325		err = msleep(&gref->event, atalk_mutex, PSOCK | PCATCH, "AT read", 0);
326		gref->sevents &= ~POLLMSG;
327		if (err != 0)
328			return err;
329		KERNEL_DEBUG(DBG_ADSP_ATRW, 1, gref, gref->rdhead, mhead, gbuf_next(mhead));
330	}
331
332	if (gref->errno)
333		return EPIPE;
334	if ((gref->rdhead = gbuf_next(mhead)) == 0)
335		gref->rdtail = 0;
336
337	KERNEL_DEBUG(DBG_ADSP_ATRW, 2, gref, gref->rdhead, mhead, gbuf_next(mhead));
338
339
340//##### LD TEST 08/05
341//	simple_lock(&gref->lock);
342
343	gbuf_next(mhead) = 0;
344
345	for (mprev=0, m=mhead; m && len; len-=clen) {
346		if ((clen = gbuf_len(m)) > 0) {
347			if (clen > len)
348				clen = len;
349			uio->uio_rw = UIO_READ;
350			if ((res = uiomove((caddr_t)gbuf_rptr(m),
351					   clen, uio))) {
352				KERNEL_DEBUG(DBG_ADSP_ATRW, 3, m, clen,
353					     len, gbuf_cont(m));
354				break;
355			}
356			if (gbuf_len(m) > len) {
357				gbuf_rinc(m,clen);
358				break;
359			}
360		}
361		mprev = m;
362		m = gbuf_cont(m);
363	}
364	if (m) {
365		KERNEL_DEBUG(DBG_ADSP_ATRW, 4, m, gbuf_len(m), mprev, gref->rdhead);
366		if (mprev)
367			gbuf_cont(mprev) = 0;
368		else
369			mhead = 0;
370		if (gref->rdhead == 0)
371			gref->rdtail = m;
372		gbuf_next(m) = gref->rdhead;
373		gref->rdhead = m;
374	}
375	if (mhead)
376		gbuf_freem(mhead);
377//### LD TEST
378//	simple_unlock(&gref->lock);
379    } else {
380  	if (gref->writeable) {
381		while (!(*gref->writeable)(gref)) {
382			/* flow control on, wait to be enabled to write */
383			gref->sevents |= POLLSYNC;
384			err = msleep(&gref->event, atalk_mutex, PSOCK | PCATCH, "AT write", 0);
385			gref->sevents &= ~POLLSYNC;
386			if (err != 0)
387				return err;
388		}
389	}
390
391
392	/* allocate a buffer to copy in the write data */
393	if ((m = gbuf_alloc(AT_WR_OFFSET+len, PRI_MED)) == 0)
394		return ENOBUFS;
395	gbuf_rinc(m,AT_WR_OFFSET);
396	gbuf_wset(m,len);
397
398	/* copy in the write data */
399	uio->uio_rw = UIO_WRITE;
400	if ((res = uiomove((caddr_t)gbuf_rptr(m), len, uio))) {
401#ifdef APPLETALK_DEBUG
402		kprintf("_ATrw: UIO_WRITE: res=%d\n", res);
403#endif
404		gbuf_freeb(m);
405		return EIO;
406	}
407
408	/* forward the write data to the appropriate protocol module */
409	gref_wput(gref, m);
410  }
411
412  return 0;
413} /* _ATrw */
414
415int _ATread(
416	struct fileproc *fp,
417	struct uio *uio,
418	__unused int flags,
419	vfs_context_t ctx)
420{
421     int stat;
422
423	atalk_lock();
424	stat = _ATrw(fp, UIO_READ, uio, ctx);
425	atalk_unlock();
426	return stat;
427}
428
429int _ATwrite(
430	struct fileproc *fp,
431	struct uio *uio,
432	__unused int flags,
433	vfs_context_t ctx)
434{
435	int stat;
436
437	atalk_lock();
438	stat = _ATrw(fp, UIO_WRITE, uio, ctx);
439	atalk_unlock();
440
441	return stat;
442}
443
444/* Most of the processing from _ATioctl, so that it can be called
445   from the new ioctl code */
446/* bms:  update to be callable from kernel */
447int at_ioctl(gref_t *gref, u_long cmd, caddr_t arg, int fromKernel)
448{
449    int err = 0, len;
450    u_int size;
451    gbuf_t *m, *mdata;
452    ioc_t *ioc;
453    user_addr_t user_arg;
454    user_ioccmd_t user_ioccmd;
455	boolean_t is64bit;
456
457    /* error if not for us */
458    if ((cmd  & 0xffff) != 0xff99)
459        return EOPNOTSUPP;
460
461	size = IOCPARM_LEN(cmd);
462	if (size != sizeof(user_addr_t))
463		return EINVAL;
464
465	user_arg = *((user_addr_t *)arg);
466
467    /* copy in ioc command info */
468    is64bit = proc_is64bit(current_proc());
469    if (fromKernel) {
470    	ioccmd_t	tmp;
471        bcopy (CAST_DOWN(caddr_t, user_arg), &tmp, sizeof (tmp));
472        ioccmd_t_32_to_64(&tmp, &user_ioccmd);
473    }
474    else {
475		if (is64bit) {
476			err = copyin(user_arg, (caddr_t)&user_ioccmd, sizeof(user_ioccmd));
477    	}
478    	else {
479	    	ioccmd_t	tmp;
480			err = copyin(user_arg, (caddr_t)&tmp, sizeof(tmp));
481        	ioccmd_t_32_to_64(&tmp, &user_ioccmd);
482    	}
483    	if (err != 0) {
484#ifdef APPLETALK_DEBUG
485			kprintf("at_ioctl: err = %d, copyin(%llx, %x, %d)\n", err,
486              		user_arg, (caddr_t)&user_ioccmd, sizeof(user_ioccmd));
487#endif
488            return err;
489        }
490    }
491
492    /* allocate a buffer to create an ioc command
493       first mbuf contains ioc command */
494    if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) == 0)
495        return ENOBUFS;
496    gbuf_wset(m, sizeof(ioc_t));    /* mbuf->m_len */
497    gbuf_set_type(m, MSG_IOCTL);    /* mbuf->m_type */
498
499    /* create the ioc command
500       second mbuf contains the actual ASP command */
501    if (user_ioccmd.ic_len) {
502        if ((gbuf_cont(m) = gbuf_alloc(user_ioccmd.ic_len, PRI_HI)) == 0) {
503            gbuf_freem(m);
504#ifdef APPLETALK_DEBUG
505			kprintf("at_ioctl: gbuf_alloc err=%d\n",ENOBUFS);
506#endif
507            return ENOBUFS;
508        }
509        gbuf_wset(gbuf_cont(m), user_ioccmd.ic_len);     /* mbuf->m_len */
510        if (fromKernel)
511            bcopy (CAST_DOWN(caddr_t, user_ioccmd.ic_dp), gbuf_rptr(gbuf_cont(m)), user_ioccmd.ic_len);
512        else {
513            if ((err = copyin(user_ioccmd.ic_dp, (caddr_t)gbuf_rptr(gbuf_cont(m)), user_ioccmd.ic_len)) != 0) {
514                gbuf_freem(m);
515                return err;
516            }
517        }
518    }
519    ioc = (ioc_t *) gbuf_rptr(m);
520    ioc->ioc_cmd = user_ioccmd.ic_cmd;
521    ioc->ioc_count = user_ioccmd.ic_len;
522    ioc->ioc_error = 0;
523    ioc->ioc_rval = 0;
524
525    /* send the ioc command to the appropriate recipient */
526	gref_wput(gref, m);
527
528    /* wait for the ioc ack */
529    while ((m = gref->ichead) == 0) {
530        gref->sevents |= POLLPRI;
531#ifdef APPLETALK_DEBUG
532		kprintf("sleep gref = 0x%x\n", (unsigned)gref);
533#endif
534		err = msleep(&gref->iocevent, atalk_mutex, PSOCK | PCATCH, "AT ioctl", 0);
535		gref->sevents &= ~POLLPRI;
536		if (err != 0) {
537#ifdef APPLETALK_DEBUG
538			kprintf("at_ioctl: EINTR\n");
539#endif
540			return err;
541		}
542	}
543
544	/* PR-2224797 */
545 	if (gbuf_next(m) == m)		/* error case */
546		gbuf_next(m) = 0;
547
548	gref->ichead = gbuf_next(m);
549
550
551#ifdef APPLETALK_DEBUG
552	kprintf("at_ioctl: woke up from ioc sleep gref = 0x%x\n",
553		(unsigned)gref);
554#endif
555
556    /* process the ioc response */
557    ioc = (ioc_t *) gbuf_rptr(m);
558    if ((err = ioc->ioc_error) == 0) {
559        user_ioccmd.ic_timout = ioc->ioc_rval;
560        user_ioccmd.ic_len = 0;
561        mdata = gbuf_cont(m);
562        if (mdata && user_ioccmd.ic_dp) {
563            user_ioccmd.ic_len = gbuf_msgsize(mdata);
564            for (len = 0; mdata; mdata = gbuf_cont(mdata)) {
565                if (fromKernel)
566                    bcopy (gbuf_rptr(mdata), CAST_DOWN(caddr_t, (user_ioccmd.ic_dp + len)), gbuf_len(mdata));
567                else {
568                    if ((err = copyout((caddr_t)gbuf_rptr(mdata), (user_ioccmd.ic_dp + len), gbuf_len(mdata))) < 0) {
569#ifdef APPLETALK_DEBUG
570						kprintf("at_ioctl: len=%d error copyout=%d from=%x to=%x gbuf_len=%x\n",
571					 			len, err, (caddr_t)gbuf_rptr(mdata), (caddr_t)&user_ioccmd.ic_dp[len], gbuf_len(mdata));
572#endif
573                        goto l_done;
574                    }
575                }
576                len += gbuf_len(mdata);
577            }
578        }
579
580        if (fromKernel) {
581			ioccmd_t	tmp;
582			ioccmd_t_64_to_32(&user_ioccmd, &tmp);
583 			bcopy (&tmp, CAST_DOWN(caddr_t, user_arg), sizeof(tmp));
584        }
585        else {
586 			if (is64bit) {
587				err = copyout((caddr_t)&user_ioccmd, user_arg, sizeof(user_ioccmd));
588			}
589			else {
590				ioccmd_t	tmp;
591				ioccmd_t_64_to_32(&user_ioccmd, &tmp);
592				err = copyout((caddr_t)&tmp, user_arg, sizeof(tmp));
593			}
594            if (err != 0) {
595                goto l_done;
596            }
597        }
598    }
599
600l_done:
601	gbuf_freem(m);
602	/*kprintf("at_ioctl: I_done=%d\n", err);*/
603	return err;
604} /* at_ioctl */
605
606int _ATioctl(
607	struct fileproc *fp,
608	u_long cmd,
609	register caddr_t arg,
610	__unused vfs_context_t ctx)
611{
612	int err;
613	gref_t *gref;
614
615	atalk_lock();
616	/* No need to get a reference on fp as it already has one */
617	if ((err = atalk_getref_locked(fp, 0, &gref, 0, 0)) != 0) {
618#ifdef APPLETALK_DEBUG
619		kprintf("_ATioctl: atalk_getref err = %d\n", err);
620#endif
621	}
622	else
623	     err = at_ioctl(gref, cmd, arg, 0);
624
625	atalk_unlock();
626
627	return err;
628}
629
630int _ATselect(fp, which, wql, ctx)
631	struct fileproc *fp;
632	int which;
633	void * wql;
634	vfs_context_t ctx;
635{
636	int err, rc = 0;
637	gref_t *gref;
638	proc_t proc = vfs_context_proc(ctx);
639
640	/* Radar 4128949: Drop the proc_fd lock here to avoid lock inversion issues with the other AT calls
641      * select() is already holding a reference on the fd, so it won't go away during the time it is unlocked.
642      */
643	proc_fdunlock(proc);
644
645	atalk_lock();
646	/* no need to drop the iocount as select covers that */
647	err = atalk_getref_locked(fp, 0, &gref, 0, 0);
648	atalk_unlock();
649
650	/* Safe to re-grab the proc_fdlock at that point */
651	proc_fdlock(proc);
652	if (err != 0)
653		rc = 1;
654	else {
655	     if (which == FREAD) {
656		  if (gref->rdhead || (gref->readable && (*gref->readable)(gref)))
657		       rc = 1;
658		  else {
659		       gref->sevents |= POLLIN;
660		       selrecord(proc, &gref->si, wql);
661		  }
662	     }
663	     else if (which == POLLOUT) {
664		  if (gref->writeable) {
665		       if ((*gref->writeable)(gref))
666			    rc = 1;
667		       else {
668			    gref->sevents |= POLLOUT;
669			    selrecord(proc, &gref->si, wql);
670		       }
671		  } else
672		       rc = 1;
673	     }
674	}
675
676	return rc;
677}
678
679int _ATkqfilter(
680	__unused struct fileproc *fp,
681	__unused struct knote *kn,
682	__unused vfs_context_t ctx)
683{
684	return (EOPNOTSUPP);
685}
686
687void atalk_putnext(gref, m)
688	gref_t *gref;
689	gbuf_t *m;
690{
691
692
693	/* *** potential leak? *** */
694	gbuf_next(m) = 0;
695
696	switch (gbuf_type(m)) {
697	case MSG_IOCACK:
698	case MSG_IOCNAK:
699		if (gref->ichead)
700			gbuf_next(gref->ichead) = m;
701		else {
702			gref->ichead = m;
703			if (gref->sevents & POLLPRI) {
704#ifdef APPLETALK_DEBUG
705				kprintf("wakeup gref = 0x%x\n", (unsigned)gref);
706#endif
707				wakeup(&gref->iocevent);
708			}
709		}
710		break;
711	case MSG_ERROR:
712		/* *** this processing was moved to atalk_notify *** */
713		panic("atalk_putnext receved MSG_ERROR");
714		break;
715	default:
716		if (gref->errno)
717		   gbuf_freem(m);
718		else
719		   if (gref->rdhead) {
720			gbuf_next(gref->rdtail) = m;
721			gref->rdtail = m;
722		    } else {
723			gref->rdhead = m;
724			if (gref->sevents & POLLMSG) {
725				gref->sevents &= ~POLLMSG;
726				wakeup(&gref->event);
727			}
728			if (gref->sevents & POLLIN) {
729				gref->sevents &= ~POLLIN;
730				selwakeup(&gref->si);
731			}
732			gref->rdtail = m;
733		    }
734	} /* switch gbuf_type(m) */
735
736} /* atalk_putnext */
737
738void atalk_enablew(gref)
739	gref_t *gref;
740{
741	if (gref->sevents & POLLSYNC)
742		wakeup(&gref->event);
743}
744
745void atalk_flush(gref)
746	gref_t *gref;
747{
748
749	if (gref->rdhead) {
750		gbuf_freel(gref->rdhead);
751		gref->rdhead = 0;
752	}
753	if (gref->ichead) {
754		gbuf_freel(gref->ichead);
755		gref->ichead = 0;
756	}
757}
758
759/*
760 * Notify an appletalk user of an asynchronous error;
761 * just wake up so that they can collect error status.
762 */
763void atalk_notify(gref, errno)
764	register gref_t *gref;
765	int errno;
766{
767
768	if (gref->atpcb_socket) {
769	    /* For DDP --
770	       This section is patterned after udp_notify() in
771	       netinet/udp_usrreq.c
772	    */
773	    gref->atpcb_socket->so_error = errno;
774	    sorwakeup(gref->atpcb_socket);
775	    sowwakeup(gref->atpcb_socket);
776	} else {
777	    /* for ATP, ASP, and ADSP */
778	    if (gref->errno == 0) {
779		gref->errno = errno;
780		/* clear out data waiting to be read */
781		if (gref->rdhead) {
782			gbuf_freel(gref->rdhead);
783			gref->rdhead = 0;
784		}
785		/* blocked read */
786		if (gref->sevents & POLLMSG) {
787			gref->sevents &= ~POLLMSG;
788			wakeup(&gref->event);
789		}
790		/* select */
791		if (gref->sevents & POLLIN) {
792			gref->sevents &= ~POLLIN;
793			selwakeup(&gref->si);
794		}
795	    }
796	}
797} /* atalk_notify */
798
799void atalk_notify_sel(gref)
800	gref_t *gref;
801{
802
803	if (gref->sevents & POLLIN) {
804		gref->sevents &= ~POLLIN;
805		selwakeup(&gref->si);
806	}
807}
808
809int atalk_peek(gref, event)
810	gref_t *gref;
811	unsigned char *event;
812{
813	int rc;
814
815	if (gref->rdhead) {
816		*event = *gbuf_rptr(gref->rdhead);
817		rc = 0;
818	} else
819		rc = -1;
820
821	return rc;
822}
823
824#if 0
825static gbuf_t *trace_msg;
826
827void atalk_settrace(char * str, p1, p2, p3, p4, p5)
828{
829	int len;
830	gbuf_t *m, *nextm;
831	char trace_buf[256];
832
833	sprintf(trace_buf, str, p1, p2, p3, p4, p5);
834	len = strlen(trace_buf);
835#ifdef APPLETALK_DEBUG
836	kprintf("atalk_settrace: gbufalloc size=%d\n", len+1);
837#endif
838	if ((m = gbuf_alloc(len+1, PRI_MED)) == 0)
839		return;
840	gbuf_wset(m,len);
841	strcpy(gbuf_rptr(m), trace_buf);
842	if (trace_msg) {
843		for (nextm=trace_msg; gbuf_cont(nextm); nextm=gbuf_cont(nextm)) ;
844		gbuf_cont(nextm) = m;
845	} else
846		trace_msg = m;
847}
848
849void atalk_gettrace(m)
850	gbuf_t *m;
851{
852	if (trace_msg) {
853		gbuf_cont(m) = trace_msg;
854		trace_msg = 0;
855	}
856}
857#endif /* 0 */
858
859#define GREF_PER_BLK 32
860static gref_t *gref_free_list = 0;
861extern gbuf_t *atp_resource_m;
862
863int gref_alloc(grefp)
864	gref_t **grefp;
865{
866	int i;
867	gbuf_t *m;
868	gref_t *gref, *gref_array;
869
870	*grefp = (gref_t *)NULL;
871
872	if (gref_free_list == 0) {
873#ifdef APPLETALK_DEBUG
874		kprintf("gref_alloc: gbufalloc size=%d\n", GREF_PER_BLK*sizeof(gref_t));
875#endif
876		if ((m = gbuf_alloc(GREF_PER_BLK*sizeof(gref_t),PRI_HI)) == 0)
877			return ENOBUFS;
878		bzero(gbuf_rptr(m), GREF_PER_BLK*sizeof(gref_t));
879		gref_array = (gref_t *)gbuf_rptr(m);
880		for (i=0; i < GREF_PER_BLK-1; i++)
881			gref_array[i].atpcb_next = (gref_t *)&gref_array[i+1];
882		gbuf_cont(m) = atp_resource_m;
883		atp_resource_m = m;
884		gref_array[i].atpcb_next = gref_free_list;
885		gref_free_list = (gref_t *)&gref_array[0];
886	}
887
888	gref = gref_free_list;
889	gref_free_list = gref->atpcb_next;
890	ATEVENTINIT(gref->event);
891	ATEVENTINIT(gref->iocevent);
892
893	/* *** just for now *** */
894	gref->atpcb_socket = (struct socket *)NULL;
895
896	*grefp = gref;
897	return 0;
898} /* gref_alloc */
899
900/* bms:  make gref_close callable from kernel */
901int gref_close(gref_t *gref)
902{
903	int rc;
904
905	switch (gref->proto) {
906
907	/* ATPROTO_DDP and ATPROTO_LAP have been replaced with
908	   BSD-style socket interface. */
909
910	case ATPROTO_ATP:
911		rc = atp_close(gref, 1); break;
912	case ATPROTO_ASP:
913	  	rc = asp_close(gref); break;
914#ifdef AURP_SUPPORT
915	case ATPROTO_AURP:
916		rc = aurp_close(gref); break;
917		break;
918#endif
919	case ATPROTO_ADSP:
920		rc = adsp_close(gref); break;
921	default:
922		rc = 0;
923		break;
924	}
925
926	if (rc == 0) {
927		atalk_flush(gref);
928		selthreadclear(&gref->si);
929
930		/* from original gref_free() */
931		bzero((char *)gref, sizeof(gref_t));
932		gref->atpcb_next = gref_free_list;
933		gref_free_list = gref;
934	}
935
936	return rc;
937}
938
939/*
940	temp fix for bug 2731148  - until this code is re-written to use standard clusters
941	Deletes any free clusters on the free list.
942*/
943void atp_delete_free_clusters(__unused void *junk)
944{
945	caddr_t cluster;
946	caddr_t cluster_list;
947
948	/* check for free clusters on the free_cluster_list to be deleted */
949
950	untimeout(&atp_delete_free_clusters, NULL);
951
952	lck_mtx_lock(atalk_cluster_lock);
953
954	atp_free_cluster_timeout_set = 0;
955
956	cluster_list = atp_free_cluster_list;
957	atp_free_cluster_list = NULL;
958
959	lck_mtx_unlock(atalk_cluster_lock);
960
961	while ((cluster = cluster_list))
962	{
963		cluster_list = *((caddr_t*)cluster);
964		FREE(cluster, M_MCLUST);
965	}
966}
967
968
969/*
970   Used as the "free" routine for over-size clusters allocated using
971   m_lgbuf_alloc().
972*/
973
974void m_lgbuf_free(caddr_t, u_int, caddr_t);
975
976void m_lgbuf_free(
977     caddr_t buf,
978     __unused u_int size,
979     __unused caddr_t arg) /* not needed, but they're in m_free() */
980{
981	int t;
982
983	/* move to free_cluster_list to be deleted later */
984	caddr_t cluster = (caddr_t)buf;
985
986	lck_mtx_lock(atalk_cluster_lock);
987
988	*((caddr_t*)cluster) = atp_free_cluster_list;
989	atp_free_cluster_list = cluster;
990
991	if ((t = atp_free_cluster_timeout_set) == 0)
992		atp_free_cluster_timeout_set = 1;
993
994	lck_mtx_unlock(atalk_cluster_lock);
995
996	if (t == 0)
997		timeout(&atp_delete_free_clusters, NULL, (1 * HZ));
998}
999
1000/*
1001  Used to allocate an mbuf when there is the possibility that it may
1002  need to be larger than the size of a standard cluster.
1003*/
1004
1005struct mbuf *m_lgbuf_alloc(size, wait)
1006	int size, wait;
1007{
1008	struct mbuf *m;
1009
1010	if (atp_free_cluster_list)
1011		atp_delete_free_clusters(NULL);	/* delete any free clusters on the free list */
1012
1013	/* Radar 5398094
1014	 * check that the passed size is within admissible boundaries
1015	 * The max data size being ASP of 4576 (8 * ATP_DATA_SIZE),
1016	 * allow for extra space for control data
1017	 */
1018
1019	if (size < 0 || size > (ATP_DATA_SIZE * 10))
1020		return(NULL);
1021
1022	/* If size is too large, allocate a cluster, otherwise, use the
1023	   standard mbuf allocation routines.*/
1024	if (size > MCLBYTES) {
1025		void *buf;
1026		if (NULL ==
1027		    (buf = (void *)_MALLOC(size, M_MCLUST,
1028					   (wait)? M_WAITOK: M_NOWAIT))) {
1029			return(NULL);
1030		}
1031		if (NULL ==
1032		    (m = m_clattach(NULL, MSG_DATA, buf, m_lgbuf_free, size, 0,
1033				    (wait)? M_WAIT: M_DONTWAIT))) {
1034			m_lgbuf_free(buf, 0, 0);
1035			return(NULL);
1036		}
1037	} else {
1038		m = m_gethdr(((wait)? M_WAIT: M_DONTWAIT), MSG_DATA);
1039		if (m && ((size_t)size > MHLEN)) {
1040			MCLGET(m, ((wait)? M_WAIT: M_DONTWAIT));
1041			if (!(m->m_flags & M_EXT)) {
1042				(void)m_free(m);
1043				return(NULL);
1044			}
1045		}
1046	}
1047
1048	return(m);
1049} /* m_lgbuf_alloc */
1050
1051/*
1052   gbuf_alloc() is a wrapper for m_lgbuf_alloc(), which is used to
1053   allocate an mbuf when there is the possibility that it may need
1054   to be larger than the size of a standard cluster.
1055
1056   gbuf_alloc() sets the mbuf lengths, unlike the standard mbuf routines.
1057*/
1058
1059gbuf_t *gbuf_alloc_wait(size, wait)
1060     int size, wait;
1061{
1062	gbuf_t *m = (gbuf_t *)m_lgbuf_alloc(size, wait);
1063
1064	/* Standard mbuf allocation routines assume that the caller
1065	   will set the size. */
1066	if (m) {
1067		m->m_pkthdr.len = size;
1068		m->m_len = size;
1069	}
1070
1071	return(m);
1072}
1073
1074int gbuf_msgsize(m)
1075	gbuf_t *m;
1076{
1077	int size;
1078
1079	for (size=0; m; m=gbuf_cont(m))
1080		size += gbuf_len(m);
1081	return size;
1082}
1083
1084int append_copy(m1, m2, wait)
1085     struct mbuf *m1, *m2;
1086     int wait;
1087{
1088	if ((!(m1->m_flags & M_EXT)) && (!(m2->m_flags & M_EXT)) &&
1089	    (m_trailingspace(m1) >= m2->m_len)) {
1090		/* splat the data from one into the other */
1091		bcopy(mtod(m2, caddr_t), mtod(m1, caddr_t) + m1->m_len,
1092		      (u_int)m2->m_len);
1093		m1->m_len += m2->m_len;
1094		if (m1->m_flags & M_PKTHDR)
1095		    m1->m_pkthdr.len += m2->m_len;
1096		return 1;
1097	}
1098	if ((m1->m_next = m_copym(m2, 0, m2->m_len,
1099				  (wait)? M_WAIT: M_DONTWAIT)) == NULL)
1100		return 0;
1101	return 1;
1102} /* append_copy */
1103
1104/*
1105   Copy an mbuf chain, referencing existing external storage, if any.
1106   Leave space for a header in the new chain, if the space has been
1107   left in the origin chain.
1108*/
1109struct mbuf *copy_pkt(mlist, pad)
1110     struct mbuf *mlist; /* the mbuf chain to be copied */
1111     int pad;		 /* hint as to how long the header might be
1112			    If pad is < 0, leave the same amount of space
1113			    as there was in the original. */
1114{
1115	struct mbuf *new_m;
1116	int len;
1117
1118	if (pad < 0)
1119		len = m_leadingspace(mlist);
1120	else
1121		len = min(pad, m_leadingspace(mlist));
1122
1123	/* preserve space for the header at the beginning of the mbuf */
1124	if (len) {
1125		mlist->m_data -= (len);
1126		mlist->m_len += (len);
1127		if (mlist->m_flags & M_PKTHDR)
1128		    mlist->m_pkthdr.len += (len);
1129		new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1130		m_adj(mlist, len);
1131		m_adj(new_m, len);
1132	} else
1133		new_m = m_copym(mlist, 0, M_COPYALL, M_DONTWAIT);
1134
1135	return(new_m);
1136}
1137
1138void gbuf_linkb(m1, m2)
1139	gbuf_t *m1;
1140	gbuf_t *m2;
1141{
1142	while (gbuf_cont(m1) != 0)
1143		m1 = gbuf_cont(m1);
1144	gbuf_cont(m1) = m2;
1145}
1146
1147void gbuf_linkpkt(m1, m2)
1148	gbuf_t *m1;
1149	gbuf_t *m2;
1150{
1151	while (gbuf_next(m1) != 0)
1152		m1 = gbuf_next(m1);
1153	gbuf_next(m1) = m2;
1154}
1155
1156int gbuf_freel(m)
1157	gbuf_t *m;
1158{
1159	gbuf_t *tmp_m;
1160
1161	while ((tmp_m = m) != 0) {
1162		m = gbuf_next(m);
1163		gbuf_next(tmp_m) = 0;
1164		gbuf_freem(tmp_m);
1165	}
1166	return (0);
1167}
1168
1169/* free empty mbufs at the front of the chain */
1170gbuf_t *gbuf_strip(m)
1171     gbuf_t *m;
1172{
1173	gbuf_t *tmp_m;
1174
1175	while (m && gbuf_len(m) == 0) {
1176		tmp_m = m;
1177		m = gbuf_cont(m);
1178		gbuf_freeb(tmp_m);
1179	}
1180	return(m);
1181}
1182
1183/**************************************/
1184
1185int ddp_adjmsg(m, len)
1186	gbuf_t 		*m;
1187	int 	len;
1188{
1189	int buf_len;
1190	gbuf_t *curr_m, *prev_m;
1191
1192	if (m == (gbuf_t *)0)
1193		return 0;
1194
1195	if (len > 0) {
1196		for (curr_m=m; curr_m;) {
1197			buf_len = gbuf_len(curr_m);
1198			if (len < buf_len) {
1199				gbuf_rinc(curr_m,len);
1200				return 1;
1201			}
1202			len -= buf_len;
1203			gbuf_rinc(curr_m,buf_len);
1204			if ((curr_m = gbuf_cont(curr_m)) == 0) {
1205				gbuf_freem(m);
1206				return 0;
1207			}
1208		}
1209
1210	} else if (len < 0) {
1211		len = -len;
1212l_cont:	prev_m = 0;
1213		for (curr_m=m; gbuf_cont(curr_m);
1214			prev_m=curr_m, curr_m=gbuf_cont(curr_m)) ;
1215		buf_len = gbuf_len(curr_m);
1216		if (len < buf_len) {
1217			gbuf_wdec(curr_m,len);
1218			return 1;
1219		}
1220		if (prev_m == 0)
1221			return 0;
1222		gbuf_cont(prev_m) = 0;
1223		gbuf_freeb(curr_m);
1224		len -= buf_len;
1225		goto l_cont;
1226
1227	}
1228
1229	return 1;
1230}
1231
1232/*
1233 * The message chain, m is grown in size by len contiguous bytes.
1234 * If len is non-negative, len bytes are added to the
1235 * end of the gbuf_t chain.  If len is negative, the
1236 * bytes are added to the front. ddp_growmsg only adds bytes to
1237 * message blocks of the same type.
1238 * It returns a pointer to the new gbuf_t on sucess, 0 on failure.
1239 */
1240
1241gbuf_t *ddp_growmsg(mp, len)
1242	gbuf_t 	*mp;
1243	int 	len;
1244{
1245	gbuf_t	*m, *d;
1246
1247	if ((m = mp) == (gbuf_t *) 0)
1248		return ((gbuf_t *) 0);
1249
1250	if (len <= 0) {
1251		len = -len;
1252		if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1253			return ((gbuf_t *) 0);
1254		gbuf_set_type(d, gbuf_type(m));
1255		gbuf_wset(d,len);
1256		/* link in new gbuf_t */
1257		gbuf_cont(d) = m;
1258		return (d);
1259
1260	} else {
1261	        register int	count;
1262		/*
1263		 * Add to tail.
1264		 */
1265		if ((count = gbuf_msgsize(m)) < 0)
1266			return ((gbuf_t *) 0);
1267		/* find end of chain */
1268		for ( ; m; m = gbuf_cont(m)) {
1269			if (gbuf_len(m) >= count)
1270				break;
1271			count -= gbuf_len(m);
1272		}
1273		/* m now points to gbuf_t to add to */
1274		if ((d = gbuf_alloc(len, PRI_MED)) == 0)
1275			return ((gbuf_t *) 0);
1276		gbuf_set_type(d, gbuf_type(m));
1277		/* link in new gbuf_t */
1278		gbuf_cont(d) = gbuf_cont(m);
1279		gbuf_cont(m) = d;
1280		gbuf_wset(d,len);
1281		return (d);
1282	}
1283}
1284
1285/*
1286 *	return the MSG_IOCACK/MSG_IOCNAK. Note that the same message
1287 *	block is used as the vehicle, and that if there is an error return,
1288 *	then linked blocks are lopped off. BEWARE of multiple references.
1289 *	Used by other appletalk modules, so it is not static!
1290 */
1291
1292void ioc_ack(errno, m, gref)
1293     int		errno;
1294     register gbuf_t	*m;
1295     register gref_t	*gref;
1296{
1297	ioc_t *iocbp = (ioc_t *)gbuf_rptr(m);
1298
1299	/*kprintf("ioc_ack: m=%x gref=%x errno=%d\n", m, gref, errno);*/
1300	if ((iocbp->ioc_error = errno) != 0)
1301	{	/* errno != 0, then there is an error, get rid of linked blocks! */
1302
1303		if (gbuf_cont(m)) {
1304		        gbuf_freem(gbuf_cont(m));
1305		        gbuf_cont(m) = 0;
1306		}
1307	        gbuf_set_type(m, MSG_IOCNAK);
1308		iocbp->ioc_count = 0;	/* only make zero length if error */
1309		iocbp->ioc_rval = -1;
1310	} else
1311	        gbuf_set_type(m, MSG_IOCACK);
1312
1313	atalk_putnext(gref, m);
1314}
1315
1316
1317static void ioccmd_t_32_to_64( ioccmd_t *from_p, user_ioccmd_t *to_p )
1318{
1319	to_p->ic_cmd = from_p->ic_cmd;
1320	to_p->ic_timout = from_p->ic_timout;
1321	to_p->ic_len = from_p->ic_len;
1322	to_p->ic_dp = CAST_USER_ADDR_T(from_p->ic_dp);
1323}
1324
1325
1326static void ioccmd_t_64_to_32( user_ioccmd_t *from_p, ioccmd_t *to_p )
1327{
1328	to_p->ic_cmd = from_p->ic_cmd;
1329	to_p->ic_timout = from_p->ic_timout;
1330	to_p->ic_len = from_p->ic_len;
1331	to_p->ic_dp = CAST_DOWN(caddr_t, from_p->ic_dp);
1332}
1333