Source to bsd/netat/sys_glue.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 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.
 *
 */
#ifdef _AIX
#include <sys/sleep.h>
#include <sys/poll.h>
#endif
#include <sys/ioccom.h>
#include <h/sysglue.h>
#include <at/appletalk.h>
#include <at/elap.h>
#include <at/ddp.h>
#include <at/at_lap.h>
#include <at_elap.h>
#include <h/at_ddp.h>
#undef e_sleep_thread

/*definition of dbgBits moved here to avoid multiple redefinition */
dbgBits_t 	dbgBits;

int _ATsocket(proto, err, proc)
	int proto;
	int *err;
	void *proc;
{
	int fd;
	gref_t *gref;

	/* make sure the specified protocol id is valid */
	switch (proto) {
	case ATPROTO_DDP:
	case ATPROTO_LAP:
	case ATPROTO_ATP:
	case ATPROTO_ASP:
	case ATPROTO_AURP:
	case ATPROTO_ADSP:
		break;
	default:
		*err = EPROTOTYPE;
#ifdef APPLETALK_DEBUG
		kprintf("_ATsocket: error EPROTOTYPE =%d\n", *err);
#endif
		return -1;
	}

	/* allocate a protocol channel */
	if ((*err = gref_open(&gref)) != 0) {
#ifdef APPLETALK_DEBUG
		kprintf("_ATsocket: error gref_open =%d\n", *err);
#endif
		return -1;
	}
	gref->proto = proto;
#ifdef NEXT
	gref->pid = ((struct proc *)proc)->p_pid;
#endif

	/* open the specified protocol */
	switch (gref->proto) {
	case ATPROTO_DDP:
		*err = ddp_open(gref); break;
	case ATPROTO_LAP:
		*err = lap_open(gref); break;
	case ATPROTO_ATP:
		*err = atp_open(gref, 1); break;
	case ATPROTO_ASP:
		*err = asp_open(gref); break;
#ifdef AURP_SUPPORT
	case ATPROTO_AURP:
		*err = aurp_open(gref); break;
#endif
	case ATPROTO_ADSP:
		*err = adsp_open(gref); break;
	}

	/* create the descriptor for the channel */
	if (*err)
		gref->proto = ATPROTO_NONE;
	if (*err || (*err = atalk_openref(gref, &fd, proc))) {
#ifdef APPLETALK_DEBUG
		kprintf("_ATsocket: error atalk_openref =%d\n", *err);
#endif
		gref_close(gref);
		return -1;
	}
/*
	kprintf("_ATsocket: proto=%d return=%d fd=%d\n", proto, *err, fd);
*/
	return fd;
}

int _ATgetmsg(fd, ctlptr, datptr, flags, err, proc)
	int fd;
	strbuf_t *ctlptr;
	strbuf_t *datptr;
	int *flags;
	int *err;
	void *proc;
{
	int rc = -1;
	gref_t *gref;

	if ((*err = atalk_getref(0, fd, &gref, proc)) == 0) {
		switch (gref->proto) {
		case ATPROTO_ASP:
			rc = ASPgetmsg(gref, ctlptr, datptr, flags, err); break;
		case ATPROTO_AURP:
#ifdef AURP_SUPPORT
			rc = AURPgetmsg(err); break;
#endif
		default:
			*err = EPROTONOSUPPORT; break;
		}
	}


/*	kprintf("_ATgetmsg: return=%d\n", *err);*/
	return rc;
}

int _ATputmsg(fd, ctlptr, datptr, flags, err, proc)
	int fd;
	strbuf_t *ctlptr;
	strbuf_t *datptr;
	int flags;
	int *err;
	void *proc;
{
	int rc = -1;
	gref_t *gref;

	if ((*err = atalk_getref(0, fd, &gref, proc)) == 0) {
		switch (gref->proto) {
		case ATPROTO_ASP:
			rc = ASPputmsg(gref, ctlptr, datptr, flags, err); break;
		default:
			*err = EPROTONOSUPPORT; break;
		}
	}

/*	kprintf("_ATputmsg: return=%d\n", *err); */
	return rc;
}

int _ATclose(fp, proc)
	void *fp;
	void *proc;
{
	int err;
	gref_t *gref;

	if ((err = atalk_closeref(fp, &gref)) != 0)
		return err;

	gref_close(gref);
	return 0;
}

int _ATrw(fp, rw, uio, ext)
	void *fp;
	enum uio_rw rw;
	struct uio *uio;
	int ext;
{
	void gref_wput();
	int s, err, len, rlen, clen, res;
	gref_t *gref;
	gbuf_t *m, *mhead, *mprev;

	if ((err = atalk_getref(fp, 0, &gref, 0)) != 0)
		return err;

	if ((len = uio->uio_resid) == 0)
		return 0;

	ATDISABLE(s, gref->lock);
	if (gref->errno) {
		ATENABLE(s, gref->lock);
		return (int)gref->errno;
	}

  if (rw == UIO_READ) {
	while ((gref->errno == 0) && ((mhead = gref->rdhead) == 0)) {
		gref->sevents |= POLLMSG;
		err = tsleep(&gref->event, PSOCK | PCATCH, "AT read", 0);
		gref->sevents &= ~POLLMSG;
		if (err != 0) {
			ATENABLE(s, gref->lock);
			return err;
		}
	}

	if (gref->errno) {
		ATENABLE(s, gref->lock);
		return EPIPE;
	}
	if ((gref->rdhead = gbuf_next(mhead)) == 0)
		gref->rdtail = 0;

	ATENABLE(s, gref->lock);

	gbuf_next(mhead) = 0;

	for (mprev=0, m=mhead, rlen=0; m && len; rlen+=clen, len-=clen) {
		if ((clen = gbuf_len(m)) > 0) {
			if (clen > len)
				clen = len;
#ifdef _AIX
			if (uiomove((caddr_t)gbuf_rptr(m), clen, UIO_READ, uio) == -1)
				break;
#else
			uio->uio_rw = UIO_READ;
			res= uiomove((caddr_t)gbuf_rptr(m), clen, uio);
			/* kprintf("_ATrw: UIO_READ: res=%d\n", res); */
			if (res == -1)
				break;
#endif
			if (gbuf_len(m) > len) {
				gbuf_rinc(m,clen);
				break;
			}
		}
		mprev = m;
		m = gbuf_cont(m);
	}
	if (m) {
		if (mprev)
			gbuf_cont(mprev) = 0;
		else
			mhead = 0;
		ATDISABLE(s, gref->lock);
		if (gref->rdhead == 0)
			gref->rdtail = m;
		gbuf_next(m) = gref->rdhead;
		gref->rdhead = m;
		ATENABLE(s, gref->lock);
	}
	if (mhead)
		gbuf_freem(mhead);

  } else {
	if (gref->writeable) {
		while (!(*gref->writeable)(gref)) {
			/* flow control on, wait to be enabled to write */ 
			gref->sevents |= POLLSYNC;
			err = tsleep(&gref->event, PSOCK | PCATCH, "AT write", 0);
			gref->sevents &= ~POLLSYNC;
			if (err != 0) {
				ATENABLE(s, gref->lock);
				return err;
			}
		}
	}

	ATENABLE(s, gref->lock);

	/* allocate a buffer to copy in the write data */
	if ((m = gbuf_alloc(AT_WR_OFFSET+len, PRI_MED)) == 0)
		return ENOBUFS;
	gbuf_rinc(m,AT_WR_OFFSET);
	gbuf_wset(m,len);

	/* copy in the write data */
#ifdef _AIX
	if (uiomove((caddr_t)gbuf_rptr(m), len, UIO_WRITE, uio) == -1) {
#else
	uio->uio_rw = UIO_WRITE;
	res= uiomove((caddr_t)gbuf_rptr(m), len, uio);
	/* kprintf("_ATrw: UIO_WRITE: res=%d\n", res); */
	if (res == -1) {
#endif
		gbuf_freeb(m);
		return EIO;
	}

	/* forward the write data to the appropriate protocol module */
	gref_wput(gref, m);
  }

	return 0;
}

int _ATread(fp, uio, cred)
	void *fp;
	struct uio *uio;
	void *cred;
{
	return _ATrw(fp, UIO_READ, uio, 0);
}

int _ATwrite(fp, uio, cred)
	void *fp;
	struct uio *uio;
	void *cred;
{
	return _ATrw(fp, UIO_WRITE, uio, 0);
}
/*
struct at_ioctl_args {
	int fdes;
	u_long cmd;
	caddr_t arg;
};
int _ATioctl(p, uap, retval)
	struct proc *p;
	register struct at_ioctl_args *uap;
	register_t *retval;
*/
int _ATioctl(fp, cmd, arg, proc)
	void *fp;
	u_long cmd;
	register caddr_t arg;
	void *proc;
{
	void gref_wput();
	int s, err, len;
	gref_t *gref;
	gbuf_t *m, *mdata;
	ioc_t *ioc;
	ioccmd_t ioccmd;


	if ((err = atalk_getref(fp, 0, &gref, 0)) != 0) {
#ifdef APPLETALK_DEBUG
		kprintf("_ATioctl: atalk_getref=%d\n", err);
#endif
		return err;
	}

	/* error if not for us */
	if ((cmd  & 0xffff) != 0xff99)
		return EOPNOTSUPP;

	/* copy in ioc command info */
/*
	kprintf("_ATioctl: arg ioccmd.ic_cmd=%x ic_len=%x gref->lock=%x, gref->event=%x\n",
		((ioccmd_t *)arg)->ic_cmd, ((ioccmd_t *)arg)->ic_len, gref->lock, gref->event);
*/
	if ((err = copyin((caddr_t)arg,
			(caddr_t)&ioccmd, sizeof(ioccmd_t))) != 0) { 
#ifdef APPLETALK_DEBUG
	  kprintf("_ATioctl: err = %d, copyin(%x, %x, %d)\n", err, (caddr_t)arg,
		  (caddr_t)&ioccmd, sizeof(ioccmd_t));
#endif
		return err;
	} 

	/* allocate a buffer to create an ioc command */
	if ((m = gbuf_alloc(sizeof(ioc_t), PRI_HI)) == 0)
		return ENOBUFS;
	gbuf_wset(m,sizeof(ioc_t));
	gbuf_set_type(m, MSG_IOCTL);

	/* create the ioc command */
	if (ioccmd.ic_len) {
		if ((gbuf_cont(m) = gbuf_alloc(ioccmd.ic_len, PRI_HI)) == 0) {
			gbuf_freem(m);
#ifdef APPLETALK_DEBUG
			kprintf("_ATioctl: gbuf_alloc err=%d\n",ENOBUFS);
#endif
			return ENOBUFS;
		}
		gbuf_wset(gbuf_cont(m),ioccmd.ic_len);
		if ((err = copyin((caddr_t)ioccmd.ic_dp,
				(caddr_t)gbuf_rptr(gbuf_cont(m)), ioccmd.ic_len)) != 0) { 
			gbuf_freem(m);
			return err;
		}
	}
	ioc = (ioc_t *)gbuf_rptr(m);
	ioc->ioc_cmd = ioccmd.ic_cmd;
	ioc->ioc_count = ioccmd.ic_len;
	ioc->ioc_error = 0;
	ioc->ioc_rval = 0;

	/* send the ioc command to the appropriate recipient */
	gref_wput(gref, m);

	/* wait for the ioc ack */
	ATDISABLE(s, gref->lock);
	while ((m = gref->ichead) == 0) {
		gref->sevents |= POLLPRI;
		err = tsleep(&gref->iocevent, PSOCK | PCATCH, "AT ioctl", 0);
		gref->sevents &= ~POLLPRI;
		if (err != 0) {
			ATENABLE(s, gref->lock);
#ifdef APPLETALK_DEBUG
			kprintf("_ATioctl: EINTR\n");
#endif
			return err;
		}
	}

/* PR-2224797 */
 	if (gbuf_next(m) == m)		/* error case */
		gbuf_next(m) = 0; 

	gref->ichead = gbuf_next(m);

	ATENABLE(s, gref->lock);


/*	kprintf("_ATioctl: woke up from tread sleep\n"); */
	/* process the ioc response */
	ioc = (ioc_t *)gbuf_rptr(m);
	if ((err = ioc->ioc_error) == 0) {
		ioccmd.ic_timout = ioc->ioc_rval;
		ioccmd.ic_len = 0;
		mdata = gbuf_cont(m);
		if (mdata && ioccmd.ic_dp) {
			ioccmd.ic_len = gbuf_msgsize(mdata);
		  for (len=0; mdata; mdata=gbuf_cont(mdata)) {
			if ((err = copyout((caddr_t)gbuf_rptr(mdata),
					(caddr_t)&ioccmd.ic_dp[len], gbuf_len(mdata))) < 0) {
#ifdef APPLETALK_DEBUG
				kprintf("_ATioctl: len=%d error copyout=%d from=%x to=%x gbuf_len=%x\n",
					 len, err, (caddr_t)gbuf_rptr(mdata), 
					 (caddr_t)&ioccmd.ic_dp[len], gbuf_len(mdata));
#endif
				goto l_done;
			}
			len += gbuf_len(mdata);
		  }
		}
		if ((err = copyout((caddr_t)&ioccmd,
				(caddr_t)arg, sizeof(ioccmd_t))) != 0) {
#ifdef APPLETALK_DEBUG
				kprintf("_ATioctl: error copyout2=%d from=%x to=%x len=%d\n",
					 err, &ioccmd, arg, sizeof(ioccmd_t));
#endif
			goto l_done;
		}
	}

l_done:
	gbuf_freem(m);
	/*kprintf("_ATioctl: I_done=%d\n", err);*/
	return err;
}

#ifndef _AIX
int _ATselect(fp, which, proc)
	void *fp;
	int which;
	void *proc;
{
	int s, err, rc = 0;
	gref_t *gref;

	if ((err = atalk_getref(fp, 0, &gref, 0)) != 0)
		return err;

	ATDISABLE(s, gref->lock);
	if (which == FREAD) {
		if (gref->rdhead || (gref->readable && (*gref->readable)(gref)))
			rc = 1;
		else {
			gref->sevents |= POLLIN;
			selrecord(proc, &gref->si);
		}
	}

	else if (which == POLLOUT) {
		if (gref->writeable) {
			if ((*gref->writeable)(gref))
				rc = 1;
			else {
				gref->sevents |= POLLOUT;
				selrecord(proc, &gref->si);
			}
		} else
			rc = 1;
	}
	ATENABLE(s, gref->lock);

	return rc;
}

#else  /* AIX code is no longer supported. */

int _ATselect(fp, corl, reqevents, retevents, notify)
	void *fp;
	int corl;
	unsigned short reqevents;
	unsigned short *retevents;
	void (*notify)();
{
	int s, err, rc = 0;
	gref_t *gref;
	unsigned short sevents = 0;

	if ((err = atalk_getref(fp, 0, &gref, 0)) != 0)
		return err;

	ATDISABLE(s, gref->lock);
	if (reqevents & POLLIN) {
		if (gref->rdhead || (gref->readable && (*gref->readable)(gref)))
			sevents |= POLLIN;
	}

	if (reqevents & POLLOUT) {
		if (gref->writeable) {
			if ((*gref->writeable)(gref))
				sevents |= POLLOUT;
		} else
			sevents |= POLLOUT;
	}

	if ((sevents == 0) && ((reqevents & POLLSYNC) == 0)) {
		if (rc = selreg(corl, 99, gref, reqevents, notify)) {
			ATENABLE(s, gref->lock);
			goto l_done;
		}

          if (reqevents & POLLIN) {
			if (gref->rdhead || (gref->readable && (*gref->readable)(gref)))
				sevents |= POLLIN;
			else
				gref->sevents |= POLLIN;
          }

          if (reqevents & POLLOUT) {
			if (gref->writeable) {
				if ((*gref->writeable)(gref))
					sevents |= POLLOUT;
				else
					gref->sevents |= POLLOUT;
			} else
				sevents |= POLLOUT;
          }
     }
	ATENABLE(s, gref->lock);
     *retevents = sevents;

l_done:
	return rc;
}

int _ATstat()
{
	return 0;
}
#endif  /* end AIX section */

void atalk_putnext(gref, m)
	gref_t *gref;
	gbuf_t *m;
{
	int s;

	ATDISABLE(s, gref->lock);

	gbuf_next(m) = 0;

	if ((gbuf_type(m) == MSG_IOCACK) || (gbuf_type(m) == MSG_IOCNAK)) {
		if (gref->ichead)
			gbuf_next(gref->ichead) = m;
		else {
			gref->ichead = m;
			if (gref->sevents & POLLPRI) {
				/*kprintf("atalk_putnext: wake up gref->event=%x\n", &gref->event);*/
				thread_wakeup(&gref->iocevent);
			}
			atalk_notify_sel(gref);
		}

	} else {
	  if (gref->errno == 0) {
		if (gbuf_type(m) == MSG_ERROR) {
	  		gref->errno = *gbuf_rptr(m);
			if (gref->rdhead) {
				gbuf_freel(gref->rdhead);
				gref->rdhead = 0;
			}
			if (gref->sevents & POLLMSG) {
				gref->sevents &= ~POLLMSG;
				/*kprintf("atalk_putnext: wake up gref->event=%x\n", &gref->event);*/
				thread_wakeup(&gref->event);
			}
			if (gref->sevents & POLLIN) {
				gref->sevents &= ~POLLIN;
				/*kprintf("atalk_putnext: selwakeup gref->si=%x\n", &gref->si); */
				selwakeup(&gref->si);
			}
		} else if (gref->rdhead) {
			gbuf_next(gref->rdtail) = m;
			gref->rdtail = m;
		} else {
			gref->rdhead = m;
			if (gref->sevents & POLLMSG) {
				gref->sevents &= ~POLLMSG;
				/*kprintf("atalk_putnext: wake up2 gref->event=%x\n", &gref->event);*/
				thread_wakeup(&gref->event);
			}
			if (gref->sevents & POLLIN) {
				gref->sevents &= ~POLLIN;
				/*kprintf("atalk_putnext: selwakeup2 gref->si=%x\n", &gref->si);*/
				selwakeup(&gref->si);
			}
			gref->rdtail = m;
		}
	  }
	}

	ATENABLE(s, gref->lock);
}

void atalk_enablew(gref)
	gref_t *gref;
{
	if (gref->sevents & POLLSYNC)
#ifdef _AIX
		e_wakeup(&gref->event);
#else
		thread_wakeup(&gref->event);
#endif
}

void atalk_flush(gref)
	gref_t *gref;
{
	int s;

	ATDISABLE(s, gref->lock);
	if (gref->rdhead) {
		gbuf_freel(gref->rdhead);
		gref->rdhead = 0;
	}
	if (gref->ichead) {
		gbuf_freel(gref->ichead);
		gref->ichead = 0;
	}
	ATENABLE(s, gref->lock);
}

void atalk_notify_sel(gref)
	gref_t *gref;
{
	int s;

	ATDISABLE(s, gref->lock);
	if (gref->sevents & POLLIN) {
		gref->sevents &= ~POLLIN;
		selwakeup(&gref->si);
	}
	ATENABLE(s, gref->lock);
}

int atalk_peek(gref, event)
	gref_t *gref;
	unsigned char *event;
{
	int s, rc;

	ATDISABLE(s, gref->lock);
	if (gref->rdhead) {
		*event = *gbuf_rptr(gref->rdhead);
		rc = 0;
	} else
		rc = -1;
	ATENABLE(s, gref->lock);

	return rc;
}

static gbuf_t *trace_msg;

void atalk_settrace(str, p1, p2, p3, p4, p5)
	char *str;
{
	int len;
	gbuf_t *m, *nextm;
	char trace_buf[256];

	sprintf(trace_buf, str, p1, p2, p3, p4, p5);
	len = strlen(trace_buf);
#ifdef APPLETALK_DEBUG
	kprintf("atalk_settrace: gbufalloc size=%d\n", len+1);
#endif
	if ((m = gbuf_alloc(len+1, PRI_MED)) == 0)
		return;
	gbuf_wset(m,len);
	strcpy(gbuf_rptr(m), trace_buf);
	if (trace_msg) {
		for (nextm=trace_msg; gbuf_cont(nextm); nextm=gbuf_cont(nextm)) ;
		gbuf_cont(nextm) = m;
	} else
		trace_msg = m;
}

void atalk_gettrace(m)
	gbuf_t *m;
{
	if (trace_msg) {
		gbuf_cont(m) = trace_msg;
		trace_msg = 0;
	}
}