/* * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * 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 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Change log: * 06/29/95 - Modified to handle flow control for writing (Tuyen Nguyen) * Modified for MP, 1996 by Tuyen Nguyen * Modified, April 9, 1997 by Tuyen Nguyen for MacOSX. */ #define RESOLVE_DBG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef notdefn struct adsp_debug adsp_dtable[1025]; int ad_entry = 0; #endif int adspAllocateCCB(gref) register gref_t *gref; /* READ queue */ { gbuf_t *ccb_mp; register CCBPtr sp; if (!(ccb_mp = gbuf_alloc(sizeof(CCB), PRI_LO))) { return (0); } bzero((caddr_t) gbuf_rptr(ccb_mp), sizeof(CCB)); gbuf_wset(ccb_mp,sizeof(CCB)); gref->info = (caddr_t) ccb_mp; sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); sp->pid = gref->pid; /* save the caller process pointer */ sp->gref = gref; /* save a back pointer to the WRITE queue */ sp->sp_mp = ccb_mp; /* and its message block */ return 1; } int adspRelease(gref) register gref_t *gref; /* READ queue */ { register CCBPtr sp; if (gref->info) { sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info)); /* Tells completion routine of close */ /* packet to remove us. */ if (sp->state == sPassive || sp->state == sClosed || sp->state == sOpening || sp->state == sListening) { if (sp->state == sListening) CompleteQueue(&sp->opb, errAborted); sp->removing = 1; /* Prevent allowing another dspClose. */ DoClose(sp, errAborted, 0); /* will remove CCB */ return 0; } else { /* sClosing & sOpen */ sp->state = sClosing; } if (CheckOkToClose(sp)) { /* going to close */ sp->sendCtl = B_CTL_CLOSE; /* Send close advice */ } else { CheckSend(sp); /* try one more time to send out data */ if (sp->state != sClosed) sp->sendCtl = B_CTL_CLOSE; /* Setup to send close advice */ } CheckSend(sp); /* and force out the close */ sp->removing = 1; /* Prevent allowing another dspClose. */ sp->state = sClosed; DoClose(sp, errAborted, 0); /* to closed and remove CCB */ } return 0; } int adspWriteHandler(gref, mp) gref_t *gref; /* WRITE queue */ gbuf_t *mp; { register ioc_t *iocbp; register struct adspcmd *ap; int error, flag; void *sp; switch(gbuf_type(mp)) { case MSG_DATA: if (gref->info == 0) { gbuf_freem(mp); return(STR_IGNORE); } /* * Fill in the global stuff */ ap = (struct adspcmd *)gbuf_rptr(mp); ap->gref = gref; ap->ioc = 0; ap->mp = mp; sp = (void *)gbuf_rptr(((gbuf_t *)gref->info)); switch(ap->csCode) { case dspWrite: if ((error = adspWrite(sp, ap))) gbuf_freem(mp); return(STR_IGNORE); case dspAttention: if ((error = adspAttention(sp, (CCBPtr)ap))) gbuf_freem(mp); return(STR_IGNORE); } case MSG_IOCTL: if (gref->info == 0) { adspioc_ack(EPROTOTYPE, mp, gref); return(STR_IGNORE); } iocbp = (ioc_t *) gbuf_rptr(mp); if (ADSP_IOCTL(iocbp->ioc_cmd)) { iocbp->ioc_count = sizeof(*ap) - 1; if (gbuf_cont(mp) == 0) { adspioc_ack(EINVAL, mp, gref); return(STR_IGNORE); } ap = (struct adspcmd *) gbuf_rptr(gbuf_cont(mp)); ap->gref = gref; ap->ioc = (caddr_t) mp; ap->mp = gbuf_cont(mp); /* request head */ ap->ioResult = 0; if ((gref->info == 0) && ((iocbp->ioc_cmd != ADSPOPEN) && (iocbp->ioc_cmd != ADSPCLLISTEN))) { ap->ioResult = errState; adspioc_ack(EINVAL, mp, gref); return(STR_IGNORE); } } else return(STR_PUTNEXT); /* pass it on down */ sp = (void *)gbuf_rptr(((gbuf_t *)gref->info)); switch(iocbp->ioc_cmd) { case ADSPOPEN: case ADSPCLLISTEN: ap->socket = ((CCBPtr)sp)->localSocket; flag = (adspMode(ap) == ocAccept) ? 1 : 0; if (flag && ap->socket) { if (adspDeassignSocket((CCBPtr)sp) >= 0) ap->socket = 0; } if ((ap->socket == 0) && ((ap->socket = (at_socket)adspAssignSocket(gref, flag)) == 0)) { adspioc_ack(EADDRNOTAVAIL, mp, gref); return(STR_IGNORE); } ap->csCode = iocbp->ioc_cmd == ADSPOPEN ? dspInit : dspCLInit; if ((error = adspInit(sp, ap)) == 0) { switch(ap->csCode) { case dspInit: /* and open the connection */ ap->csCode = dspOpen; error = adspOpen(sp, ap); break; case dspCLInit: /* ADSPCLLISTEN */ ap->csCode = dspCLListen; error = adspCLListen(sp, ap); break; } } if (error) adspioc_ack(error, mp, gref); /* if this failed req complete */ return(STR_IGNORE); case ADSPCLOSE: ap->csCode = dspClose; if ((error = adspClose(sp, ap))) { adspioc_ack(error, mp, gref); break; } break; case ADSPCLREMOVE: ap->csCode = dspCLRemove; error = adspClose(sp, ap); adspioc_ack(error, mp, gref); return(STR_IGNORE); case ADSPCLDENY: ap->csCode = dspCLDeny; if ((error = adspCLDeny(sp, (CCBPtr)ap))) { adspioc_ack(error, mp, gref); } return(STR_IGNORE); case ADSPSTATUS: ap->csCode = dspStatus; if ((error = adspStatus(sp, ap))) { adspioc_ack(error, mp, gref); } return(STR_IGNORE); case ADSPREAD: ap->csCode = dspRead; if ((error = adspRead(sp, ap))) { adspioc_ack(error, mp, gref); } return(STR_IGNORE); case ADSPATTENTION: ap->csCode = dspAttention; if ((error = adspReadAttention((CCBPtr)sp, ap))) { adspioc_ack(error, mp, gref); } return(STR_IGNORE); case ADSPOPTIONS: ap->csCode = dspOptions; if ((error = adspOptions(sp, ap))) { adspioc_ack(error, mp, gref); } return(STR_IGNORE); case ADSPRESET: ap->csCode = dspReset; if ((error = adspReset(sp, ap))) { adspioc_ack(error, mp, gref); } return(STR_IGNORE); case ADSPNEWCID: ap->csCode = dspNewCID; if ((error = adspNewCID(sp, ap))) { adspioc_ack(error, mp, gref); } return(STR_IGNORE); default: return(STR_PUTNEXT); /* pass it on down */ } return(STR_IGNORE); case MSG_PROTO: default: gbuf_freem(mp); } return(STR_IGNORE); } int adspReadHandler(gref, mp) gref_t *gref; gbuf_t *mp; { int error; switch(gbuf_type(mp)) { case MSG_DATA: if ((error = adspPacket(gref, mp))) { gbuf_freem(mp); } break; case MSG_IOCTL: default: return(STR_PUTNEXT); break; } return(STR_IGNORE); } /* * adsp_sendddp() * * Description: * This procedure a formats a DDP datagram header and calls the * DDP module to queue it for routing and transmission according to * the DDP parameters. We always take control of the datagram; * if there is an error we free it, otherwise we pass it to the next * layer. We don't need to set the src address fileds because the * DDP layer fills these in for us. * * Calling Sequence: * ret_status = adsp_sendddp(q, sp, mp, length, dstnetaddr, ddptype); * * Formal Parameters: * sp Caller stream pointer * mp gbuf_t chain containing the datagram to transmit * The first mblk contains the ADSP header and space * for the DDP header. * length size of data portion of datagram * dstnetaddr address of 4-byte destination internet address * ddptype DDP protocol to assign to the datagram * * Completion Status: * 0 Procedure successful completed. * EMSGSIZE Specified datagram length is too big. * * Side Effects: * NONE */ int adsp_sendddp(sp, mp, length, dstnetaddr, ddptype) CCBPtr sp; gbuf_t *mp; int length; AddrUnion *dstnetaddr; int ddptype; { DDPX_FRAME *ddp; gbuf_t *mlist = mp; if (mp == 0) return EINVAL; if (length > DDP_DATA_SIZE) { gbuf_freel(mlist); return EMSGSIZE; } while (mp) { if (length == 0) length = gbuf_msgsize(mp) - DDPL_FRAME_LEN; /* Set up the DDP header */ ddp = (DDPX_FRAME *) gbuf_rptr(mp); UAS_ASSIGN_HTON(ddp->ddpx_length, (length + DDPL_FRAME_LEN)); UAS_ASSIGN(ddp->ddpx_cksm, 0); if (sp) { if (sp->useCheckSum) UAS_ASSIGN_HTON(ddp->ddpx_cksm, 1); } NET_ASSIGN(ddp->ddpx_dnet, dstnetaddr->a.net); ddp->ddpx_dnode = dstnetaddr->a.node; ddp->ddpx_source = sp ? sp->localSocket : ddp->ddpx_dest; ddp->ddpx_dest = dstnetaddr->a.socket; ddp->ddpx_type = ddptype; length = 0; mp = gbuf_next(mp); } DDP_OUTPUT(mlist); return 0; } void NotifyUser( __unused CCBPtr sp) { /* pidsig(sp->pid, SIGIO); */ } void UrgentUser( __unused CCBPtr sp) { /* pidsig(sp->pid, SIGURG); */ }