Source to bsd/netat/sys_glue.c
/*
* 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;
}
}