Source to bsd/netat/sys_dep.c


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 *	Copyright (c) 1995-1998 Apple Computer, Inc. 
 *
 *	The information contained herein is subject to change without
 *	notice and  should not be  construed as a commitment by Apple
 *	Computer, Inc. Apple Computer, Inc. assumes no responsibility
 *	for any errors that may appear.
 *
 *	Confidential and Proprietary to Apple Computer, Inc.
 *
 */
#include <h/sysglue.h>
#include <h/debug.h>
#include <sys/malloc.h>
#ifdef _AIX
	#include <sys/device.h>
#else
#include <sys/file.h>
#endif

int (*sys_ATsocket)() = 0;
int (*sys_ATgetmsg)() = 0;
int (*sys_ATputmsg)() = 0;
int (*sys_ATPsndreq)() = 0;
int (*sys_ATPsndrsp)() = 0;
int (*sys_ATPgetreq)() = 0;
int (*sys_ATPgetrsp)() = 0;

#ifndef _AIX

int ATsocket(proc, uap, retval)
	void *proc;
	struct {
	int proto;
	} *uap;
	int *retval;
{
	int err;

	if (sys_ATsocket)
		*retval = (*sys_ATsocket)(uap->proto, &err, proc);
	else {
		*retval = -1;
		err = ENXIO;
	}
	return err;
}

int ATgetmsg(proc, uap, retval)
	void *proc;
	struct {
	int fd;
	void *ctlptr;
	void *datptr;
	int *flags;
	} *uap;
	int *retval;
{
	int err;

	if (sys_ATgetmsg)
		*retval = (*sys_ATgetmsg)(uap->fd,
			uap->ctlptr, uap->datptr, uap->flags, &err, proc);
	else {
		*retval = -1;
		err = ENXIO;
	}
	return err;
}

int ATputmsg(proc, uap, retval)
	void *proc;
	struct {
	int fd;
	void *ctlptr;
	void *datptr;
	int flags;
	} *uap;
	int *retval;
{
	int err;

	if (sys_ATputmsg)
		*retval = (*sys_ATputmsg)(uap->fd,
			uap->ctlptr, uap->datptr, uap->flags, &err, proc);
	else {
		*retval = -1;
		err = ENXIO;
	}
	return err;
}

int ATPsndreq(proc, uap, retval)
	void *proc;
	struct {
	int fd;
	unsigned char *buf;
	int len;
	int nowait;
	} *uap;
	int *retval;
{
	int err;

	if (sys_ATPsndreq)
		*retval = (*sys_ATPsndreq)(uap->fd,
			uap->buf, uap->len, uap->nowait, &err, proc);
	else {
		*retval = -1;
		err= ENXIO;
	}
	return err;
}

int ATPsndrsp(proc, uap, retval)
	void *proc;
	struct {
	int fd;
	unsigned char *respbuff;
	int resplen;
	int datalen;
	} *uap;
	int *retval;
{
	int err;

	if (sys_ATPsndrsp)
		*retval = (*sys_ATPsndrsp)(uap->fd,
			uap->respbuff, uap->resplen, uap->datalen, &err, proc);
	else {
		*retval = -1;
		err = ENXIO;
	}
	return err;
}

int ATPgetreq(proc, uap, retval)
	void *proc;
	struct {
	int fd;
	unsigned char *buf;
	int buflen;
	} *uap;
	int *retval;
{
	int err;

	if (sys_ATPgetreq)
		*retval = (*sys_ATPgetreq)(uap->fd,
			uap->buf, uap->buflen, &err, proc);
	else {
		*retval = -1;
		err = ENXIO;
	}
	return err;
}

int ATPgetrsp(proc, uap, retval)
	void *proc;
	struct {
	int fd;
	unsigned char *bdsp;
	} *uap;
	int *retval;
{
	int err;

	if (sys_ATPgetrsp)
		*retval = (*sys_ATPgetrsp)(uap->fd, uap->bdsp, &err, proc);
	else {
		*retval = -1;
		err = ENXIO;
	}
	return err;
}

void *at_cl_alloc(size, wait)
     int size;    /* in bytes */
     int wait;
{
	return((void *)_MALLOC(size, M_MCLUST, (wait)? M_WAITOK: M_NOWAIT));
}

void at_cl_free(buf)
     void *buf;
{
	FREE(buf, M_MCLUST);
}

int atalk_closeref(fp, grefp)
	struct file *fp;
	gref_t **grefp;
{
	*grefp = (gref_t *)fp->f_data;
	fp->f_data = 0;
	return 0;
}

int atalk_openref(gref, retfd, proc)
	gref_t *gref;
	int *retfd;
	struct proc *proc;
{
extern int _ATread(), _ATwrite(),_ATioctl(), _ATselect(), _ATclose();
static struct fileops fileops = {_ATread, _ATwrite, _ATioctl, _ATselect, _ATclose};
	int err, fd;
	struct file *fp;

	if ((err = falloc(proc, &fp, &fd)) != 0)
		return err;
	fp->f_flag = FREAD|FWRITE;
/*##### LD 5/7/96 Warning: we don't have a "DTYPE_OTHER" for
 * Rhapsody, so defines DTYPE_ATALK as DTYPE_SOCKET...
 */
	fp->f_type = DTYPE_ATALK+1;
	fp->f_ops = &fileops;
	*fdflags(proc, fd) &= ~UF_RESERVED;
	*retfd = fd;
	fp->f_data = (void *)gref;
	gref->next = (void *)fp;
	return 0;
}

int atalk_getref(fp, fd, grefp, proc)
	struct file *fp;
	int fd;
	gref_t **grefp;
	struct proc *proc;
{
	if (fp == 0) {
               int error = fdgetf(proc, fd, &fp);

               if (error) {

			*grefp = (gref_t *)0;
			return EBADF;
		}
	}
	if ((*grefp = (gref_t *)fp->f_data) == 0)
		return EBADF;
	return 0;
}

gbuf_t *gbuf_alloc_wait(size, wait)
	int size;
	int wait;
{
	gbuf_t *m;
/*
 * ### LD 5/12/97 Allocate only a mbuf if size is ok,
 *     otherwise add a cluster.
 */
	if (size > MCLBYTES) {
		void *buf;
		if ((buf = at_cl_alloc(size, wait)) == 0) {
#ifdef APPLETALK_DEBUG
			kprintf("gbuf_alloc: size =%d at_cl_alloc failed\n", 
				size);
#endif
			return NULL;
		}
		if ((m = (gbuf_t *)gbuf_attach( buf, at_cl_free, size, 0)) == 0) {
#ifdef APPLETALK_DEBUG
		  	kprintf("gbuf_alloc: size =%d gbuf_attach failed\n", 
				size);
#endif
			at_cl_free(buf);
			return NULL;
		}
/*
		kprintf("gbuf_alloc: allocated with MALLOC m=%x size =%d \n", 
			m, size);
*/
	}	
	else {
		if (!(m = 
		      (gbuf_t *)m_gethdr((wait)? M_WAIT: M_DONTWAIT, MSG_DATA)))
			return(NULL);
		if (size > MHLEN) {
			MCLGET(m, (wait)? M_WAIT: M_DONTWAIT);
			if (!(m->m_flags & M_EXT)) {
				(void)m_free(m);
				return(NULL);
			}
		}
	}
	gbuf_next(m) = 0;
	gbuf_cont(m) = 0;
	gbuf_wset(m,0);
	return m;
} /* gbuf_alloc_wait */

gbuf_t *gbuf_alloc(size, pri)
	int size;
	int pri;
{
	return(gbuf_alloc_wait(size, FALSE));
}

void gbuf_set_type(m, mtype)
     gbuf_t *m;
     short mtype;
{
  MBUF_LOCK();
  mbstat.m_mtypes[m->m_type]--;
  m->m_type = mtype;
  mbstat.m_mtypes[mtype]++;
  MBUF_UNLOCK();
}

void gbuf_freeb(m)
	gbuf_t *m;
{
	if (m) {
/*
		kprintf("gbuf_freeb: calling m_free for m=%x\n", m);
*/
		(void)m_free((struct mbuf *)m);
	}
}

/*
 * LD 5/12/97 Added for Rhapsody, defines a m_clattach function that:
 * "Allocates an mbuf structure and attaches an external cluster."
 */

struct mbuf *m_clattach(extbuf, extfree, extsize, extarg, wait)
	caddr_t extbuf;	
	int (*extfree)();
	int extsize;
	int extarg;
	int wait;
{
        struct mbuf *m;

	m = m_gethdr(wait, MSG_DATA);
/*
	kprintf("m_clattach: for mbuf = %x of extbuf =%x extsize=%d extfree=%x\n",
		m, extbuf, extsize, extfree);
*/
        if (m == NULL)
                return (NULL);
        m->m_ext.ext_buf = extbuf;
        m->m_ext.ext_free = extfree;
        m->m_ext.ext_size = extsize;
        m->m_ext.ext_arg = extarg;
        m->m_ext.ext_refs.forward = m->m_ext.ext_refs.backward =
                        &m->m_ext.ext_refs;
        m->m_data = extbuf;
        m->m_flags |= M_EXT;
        m->m_pkthdr.len = extsize;
        m->m_len = extsize;

        return (m);

}
void *atalk_timeout(func, arg, ticks)
	void (*func)();
	void *arg;
	int ticks;
{
/*
	dPrintf(D_M_ATP,D_L_VERBOSE,
			"atalk_timeout: func=%x,arg=%x,time=%d\n", func,arg,ticks, 0, 0);
*/
	timeout(func, arg, ticks);
	return arg;
}

void atalk_untimeout(func, arg, trb)
	void (*func)();
	void *arg;
	void *trb;
{
/*
	dPrintf(D_M_ATP,D_L_VERBOSE,
		"atalk_untimeout: func=%x,arg=%x, trb=%d\n", func,arg,trb, 0, 0);
*/
	untimeout(func, arg);
}

#else  /* This AIX code (to the end of this file) is no longer supported. */

int ATsocket(proto)  /* AIX version */
	int proto;
{
	int err, rc = -1;

	if (sys_ATsocket)
		rc = (*sys_ATsocket)(proto, &err, 0);
	else
		err = ENXIO;
	if (err)
		setuerror(err);
	return rc;
}

int ATgetmsg(fd, ctlptr, datptr, flags)  /* AIX version */
	int fd;
	void *ctlptr;
	void *datptr;
	int *flags;
{
	int err, rc = -1;

	if (sys_ATgetmsg)
		rc = (*sys_ATgetmsg)(fd, ctlptr, datptr, flags, &err, 0);
	else
		err = ENXIO;
	if (err)
		setuerror(err);
	return rc;
}

int ATputmsg(fd, ctlptr, datptr, flags)  /* AIX version */
	int fd;
	void *ctlptr;
	void *datptr;
	int flags;
{
	int err, rc = -1;

	if (sys_ATputmsg)
		rc = (*sys_ATputmsg)(fd, ctlptr, datptr, flags, &err, 0);
	else
		err = ENXIO;
	if (err)
		setuerror(err);
	return rc;
}

int ATPsndreq(fd, buf, len, nowait)   /* AIX version */
	int fd;
	unsigned char *buf;
	int len;
	int nowait;
{
	int err, rc = -1;

	if (sys_ATPsndreq)
		rc = (*sys_ATPsndreq)(fd, buf, len, nowait, &err, 0);
	else
		err = ENXIO;
	if (err)
		setuerror(err);
	return rc;
}

int ATPsndrsp(fd, respbuff, resplen, datalen)   /* AIX version */
	int fd;
	unsigned char *respbuff;
	int resplen;
	int datalen;
{
	int err, rc = -1;

	if (sys_ATPsndrsp)
		rc = (*sys_ATPsndrsp)(fd, respbuff, resplen, datalen, &err, 0);
	else
		err = ENXIO;
	if (err)
		setuerror(err);
	return rc;
}

int ATPgetreq(fd, buf, buflen)  /* AIX version */
	int fd;
	unsigned char *buf;
	int buflen;
{
	int err, rc = -1;

	if (sys_ATPgetreq)
		rc = (*sys_ATPgetreq)(fd, buf, buflen, &err, 0);
	else
		err = ENXIO;
	if (err)
		setuerror(err);
	return rc;
}

int ATPgetrsp(fd, bdsp)  /* AIX version */
	int fd;
	unsigned char *bdsp;
{
	int err, rc = -1;

	if (sys_ATPgetrsp)
		rc = (*sys_ATPgetrsp)(fd, bdsp, &err, 0);
	else
		err = ENXIO;
	if (err)
		setuerror(err);
	return rc;
}

void *atalk_kalloc(size)   /* AIX version */
	int size;
{
     return (void *)xmalloc(size, 2, pinned_heap);
}

void atalk_kfree(buf)   /* AIX version */
	void *buf;
{
	xmfree(buf, pinned_heap);
}

int atalk_closeref(fp, grefp)   /* AIX version */
	struct file *fp;
	gref_t **grefp;
{
	*grefp = (gref_t *)fp->f_data;
	fp->f_data = 0;
	return 0;
}

int atalk_openref(gref, retfd, proc)  /* AIX version */
	gref_t *gref;
	int *retfd;
	void *proc;
{
extern int _ATrw(), _ATioctl(), _ATselect(), _ATclose(), _ATstat();
static struct fileops fileops = {_ATrw, _ATioctl, _ATselect, _ATclose, _ATstat};
	int err, fd;
	struct file *fp;
	void *crp;

	crp = (void *)crref();
#ifdef _AIX
	if ((err = ufdcreate(FREAD|FWRITE,
			&fileops, 0, DTYPE_OTHER, &fd, crp)) != 0)
#else
	if ((err = ufdcreate(FREAD|FWRITE,
			&fileops, 0, DTYPE_ATALK, &fd, crp)) != 0)
#endif
		return err;
	*retfd = fd;
	fp = U.U_ufd[fd].fp;
	fp->f_data = (void *)gref;
	gref->next = (void *)fp;
	return 0;
}

int atalk_getref(fp, fd, grefp, proc)  /* AIX version */
	struct file *fp;
	int fd;
	gref_t **grefp;
	struct proc *proc;
{
	if (fp == 0) {
		if ((fd < 0) || (fd > U.U_maxofile) || ((fp = U.U_ufd[fd].fp) == 0)) {
			*grefp = (gref_t *)0;
			return EBADF;
		}
	}
	if ((*grefp = (gref_t *)fp->f_data) == 0)
		return EBADF;
	return 0;
}

gbuf_t *gbuf_alloc(size, pri)  /* AIX version */
	int size;
	int pri;
{
	gbuf_t *m;

	m = (size > MHLEN) ? (gbuf_t *)m_getclustm(M_DONTWAIT, MSG_DATA, size)
		: (gbuf_t *)m_gethdr(M_DONTWAIT, MSG_DATA);
#ifdef APPLETALK_DEBUG
	kprintf("gbuf_alloc: for size = %d m=%x\n", size, m);
#endif
	gbuf_next(m) = 0;
	gbuf_cont(m) = 0;
	gbuf_wset(m,0);
	return m;
}

void gbuf_freeb(m)  /* AIX version */
	gbuf_t *m;
{
	if (m)
		m_free(m);
}

static struct trb *trb_freehead = 0;
static struct trb *trb_freetail = 0;
static struct trb *trb_pendhead = 0;
static int trb_cnt = 0;
static atlock_t trb_lock;

static void atalk_rem_timeoutcf()  /* AIX version */
{
	register int s;
	register struct trb *trb;
	register struct trb *tmp_freehead, *tmp_pendhead;

	ATDISABLE(s, trb_lock);
	tmp_freehead = trb_freehead;
	trb_freehead = 0;
	tmp_pendhead = trb_pendhead;
	trb_pendhead = 0;
	trb_cnt = 0;
	ATENABLE(s, trb_lock);
	while ((trb = tmp_pendhead) != 0) {
		tmp_pendhead = trb->to_next;
		while (tstop(trb));
		tfree(trb);
	}
	while ((trb = tmp_freehead) != 0) {
		tmp_freehead = trb->to_next;
		tfree(trb);
	}
	dPrintf(D_M_ATP,D_L_ERROR, "atalk: timer stopped!\n",0,0,0,0,0);
}

static void atalk_timeoutcf(cnt)  /* AIX version */
	int cnt;
{
	register int i;
	register struct trb *trb;

	if (trb_freehead == 0) {
		for (i=0; i < cnt-1; i++) {
			trb = (struct trb *)talloc();
			trb->to_next = trb_freehead;
			trb_freehead = trb;
			if (!i) trb_freetail = trb;
			trb_cnt++;
		}
	}
	ATLOCKINIT(trb_lock);
}

static void atalk_clock(trb)  /* AIX version */
	register struct trb *trb;
{
	register int s;
	register struct trb *next;
	void (*tof)();
	void *arg;

	ATDISABLE(s, trb_lock);
	if (trb_pendhead && trb->func) {
		/*
		 * remove the timeout from the pending queue
		 */
		if (trb_pendhead == trb)
			trb_pendhead = trb->to_next;
		else {
			for (next=trb_pendhead; next->to_next; next=next->to_next) {
				if (next->to_next == trb) {
					next->to_next = trb->to_next;
					trb->func = 0;
					break;
				}
			}
			if (trb->func) {
				dPrintf(D_M_ATP,D_L_WARNING,
					"atalk_clock: %d,%x,%x\n", trb_cnt,trb,trb_pendhead,0,0);
				/*
				 * we have not found the trb in the pending list - something
				 * has gone wrong here. maybe the trb has been returned to
				 * the free list; in which case, we should simply ignore
				 * this timeout event!
				 */
				for (next=trb_freehead; next; next=next->to_next) {
					if (next == trb)
					{
						ATENABLE(s, trb_lock);
						return;
					}
				}
				/*
				 * the trb is not in the free list either - something has
				 * really gone wacky here! all we can do now is put the
				 * trb back into the free list and hope that it will be ok.
				 */
				trb->to_next = 0;
				if (trb_freehead)
					trb_freetail->to_next = trb;
				else
					trb_freehead = trb;
				trb_freetail = trb;
				trb_cnt++;
				ATENABLE(s, trb_lock);
				return;
			}
		}

		/*
		 * process the timeout
		 */
		trb->func = 0;
		trb->to_next = 0;
		tof = trb->tof;
		trb->tof = 0;
		arg = (void *)trb->func_data;
		trb->func_data = 999;
		if (trb_freehead)
			trb_freetail->to_next = trb;
		else
			trb_freehead = trb;
		trb_freetail = trb;
		trb_cnt++;
		ATENABLE(s, trb_lock);
		if (tof) {
			dPrintf(D_M_ATP,D_L_VERBOSE, "atalk_clock: func=%x, arg=%x, %d\n",
				tof,arg,trb_cnt,0,0);
			(*tof)(arg);
		} else {
			dPrintf(D_M_ATP,D_L_ERROR, "atalk_clock: func=%x, arg=%x, %d\n",
				tof,arg,trb_cnt,0,0);
		}
	} else
		ATENABLE(s, trb_lock);
}

void *atalk_timeout(func, arg, ticks)  /* AIX version */
	void (*func)();
	void *arg;
	int ticks;
{
	register int s;
	register struct trb *trb;

	dPrintf(D_M_ATP,D_L_VERBOSE,
		"atalk_timeout: func=%x,arg=%x,time=%d, %d,%x\n", func,arg,ticks,trb_cnt,trb_pendhead);
	/*
	 * set up the timeout request
	 */
	ATDISABLE(s, trb_lock);
	if ((trb = trb_freehead) == 0) {
		ATENABLE(s, trb_lock);
		dPrintf(D_M_ATP,D_L_WARNING,
			"atalk_timeout: NO TRB! time=%d, %d\n", ticks,trb_cnt,0,0,0);
		return 0;
	}
	trb_freehead = trb->to_next;
	trb->to_next = trb_pendhead;
	trb_pendhead = trb;
	trb_cnt--;
	trb->timeout.it_value.tv_sec  =  ticks / HZ;
	trb->timeout.it_value.tv_nsec = (ticks % HZ) * (NS_PER_SEC / HZ);
	trb->knext     = 0;
	trb->kprev     = 0;
	trb->flags     = 0;
	trb->tof       = func;
	trb->func      = (void (*)())atalk_clock;
	trb->func_data = (ulong)arg;
	trb->ipri      = PL_IMP;
	trb->id        = -1;

	/*
	 * start the timeout
	 */
	ATENABLE(s, trb_lock);
	tstart(trb);
	return (void *)trb;
}

void atalk_untimeout(func, arg, trb)  /* AIX version */
	void (*func)();
	void *arg;
	register struct trb *trb;
{
	register int s;
	register struct trb *next;

	dPrintf(D_M_ATP,D_L_VERBOSE,
		"atalk_untimeout: func=%x,arg=%x, %d\n", func,arg,trb_cnt,0,0);

	ATDISABLE(s, trb_lock);
	if (trb == 0) {
		for (trb=trb_pendhead; trb; trb=trb->to_next) {
			if ((func == trb->tof) && (arg == (void *)trb->func_data))
				break;
		}
	}
	if (trb && (trb->func == (void (*)())atalk_clock)
			&& (func == trb->tof) && (arg == (void *)trb->func_data)) {
		trb->func_data = 999;
		if (!(trb->flags & T_PENDING))
			{
			trb->tof = 0;
			ATENABLE(s, trb_lock);
			return;
			}
		trb->func = 0;
		while (tstop(trb));
		if (trb_pendhead == trb)
			trb_pendhead = trb->to_next;
		else {
			for (next=trb_pendhead; next->to_next != trb; next=next->to_next) {
				if (next->to_next == 0) {
					ATENABLE(s, trb_lock);
					dPrintf(D_M_ATP,D_L_WARNING,
						"atalk_untimeout: UNKNOWN TRB %x...\n",trb,0,0,0,0);
					return;
				}
			}
			next->to_next = trb->to_next;
		}
		trb->to_next = 0;
		trb_freetail->to_next = trb;
		trb_freetail = trb;
		trb_cnt++;
	}
	ATENABLE(s, trb_lock);
}

int config_atalk(dev, cmd, uiop)  /* AIX only */
dev_t dev;
int cmd;
void *uiop;
{
	static int loaded = 0;
	int err, nest;

	err = 0;
	nest = lockl(&kernel_lock, LOCK_SHORT);

	if (cmd == CFG_INIT) {
		if (loaded)
			goto out;
		vm_protect(0, 4096, 3);
		atalk_timeoutcf(256);
		atalk_load();
		loaded = 1;

	} else if (cmd == CFG_TERM) {
		if (!loaded)
			goto out;
		atalk_rem_timeoutcf();
		atalk_unload();
		loaded = 0;

	} else
		err =  EINVAL;

out:
	if (nest != LOCK_NEST)
		unlockl(&kernel_lock);
	return(err);
}

#endif