]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netat/asp_proto.c
xnu-792.12.6.tar.gz
[apple/xnu.git] / bsd / netat / asp_proto.c
index a9302545438273f3e348a61acd4a010ffeaeaa87..4fd149125627668343d10b34a495df7f64294b97 100644 (file)
@@ -1,23 +1,31 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (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.
+ * Copyright (c) 2006 Apple Computer, Inc. All Rights Reserved.
  * 
- * This 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_OSREFERENCE_HEADER_START@
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * 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_LICENSE_OSREFERENCE_HEADER_END@
  */
 /*
  *     Copyright (c) 1995 Apple Computer, Inc. 
@@ -40,6 +48,7 @@
 #include <sys/mbuf.h>
 #include <sys/ioctl.h>
 #include <sys/malloc.h>
+#include <kern/locks.h>
 #include <sys/socket.h>
 #include <sys/socketvar.h>
 
@@ -81,11 +90,10 @@ void asp_init();
 void asp_ack_reply();
 void asp_nak_reply();
 void asp_clock();
-void asp_clock_funnel();
+void asp_clock_locked(void *);
 int  asp_open();
 int  asp_close();
 int  asp_wput();
-void atp_retry_req();
 StaticProc asp_scb_t *asp_find_scb();
 StaticProc asp_scb_t *asp_scb_alloc();
 
@@ -98,13 +106,14 @@ StaticProc void asp_timout();
 StaticProc void asp_untimout();
 StaticProc void asp_hangup();
 StaticProc void asp_send_tickle();
-StaticProc void asp_send_tickle_funnel();
+StaticProc void asp_send_tickle_locked(void *);
 StaticProc void asp_accept();
 StaticProc int  asp_send_req();
 
 extern at_ifaddr_t *ifID_home;
 extern int atp_pidM[];
 extern gref_t *atp_inputQ[];
+extern lck_mtx_t *atalk_mutex;
 gbuf_t *scb_resource_m = 0;
 unsigned char asp_inpC[256];
 asp_scb_t *asp_scbQ[256];
@@ -266,7 +275,7 @@ asp_close(gref)
         */
        scb->tmo_cnt = 0;
        asp_untimout(asp_hangup, scb);
-       untimeout(asp_send_tickle_funnel, (void *)scb); /* added for 2225395 */
+       untimeout(asp_send_tickle_locked, (void *)scb); /* added for 2225395 */
 
        /*
         * free the asp session control block
@@ -371,7 +380,7 @@ void trace_end(str)
        dPrintf(D_M_ASP, D_L_TRACE,
                ("  %s: %s\n", str, mbuf_totals()));
 }
-#endif AT_MBUF_TRACE
+#endif /* AT_MBUF_TRACE */
 
 /*
  * the write routine
@@ -494,7 +503,7 @@ int asp_wput(gref, m)
 
        case ASPIOC_GetLocEntity:
                if ((gbuf_cont(mioc) == 0) || (scb->atp_state == 0)) {
-                       asp_iocnak(gref, mioc, EPROTO);
+                       asp_iocnak(gref, mioc, EPROTOTYPE);
                        return 0;
                }
                *(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->loc_addr;
@@ -502,7 +511,7 @@ int asp_wput(gref, m)
 
        case ASPIOC_GetRemEntity:
                if ((gbuf_cont(mioc) == 0) || (scb->atp_state == 0)) {
-                       asp_iocnak(gref, mioc, EPROTO);
+                       asp_iocnak(gref, mioc, EPROTOTYPE);
                        return 0;
                }
                *(at_inet_t *)gbuf_rptr(gbuf_cont(mioc)) = scb->rem_addr;
@@ -510,7 +519,7 @@ int asp_wput(gref, m)
 
        case ASPIOC_GetSession:
                if ((mdata = gbuf_cont(mioc)) == 0) {
-                       asp_iocnak(gref, mioc, EPROTO);
+                       asp_iocnak(gref, mioc, EPROTOTYPE);
                        return 0;
                }
                addr = (at_inet_t *)gbuf_rptr(mdata);
@@ -519,11 +528,11 @@ int asp_wput(gref, m)
                server_scb = asp_scbQ[addr->socket];
 /*### LD 10/28/97: changed to make sure we're not accessing a null server_scb */
                if (server_scb == 0) {
-                       asp_iocnak(gref, mioc, EPROTO);
+                       asp_iocnak(gref, mioc, EPROTOTYPE);
                        return 0;
                }
                if (server_scb->sess_ioc == 0) {
-                       asp_iocnak(gref, mioc, EPROTO);
+                       asp_iocnak(gref, mioc, EPROTOTYPE);
                        return 0;
                }
 
@@ -580,8 +589,9 @@ int asp_wput(gref, m)
                aw.param2 = 0;
                scb->ioc_wait = (unsigned char)(iocbp->ioc_cmd & 0xff);
                iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF;
+               /* bms:  make sure this is an ALO request */
                asp_send_req(gref, mioc, &status_cmd->SLSEntityIdentifier,
-                            &status_cmd->Retry, &aw, 1, ASPSTATE_WaitingForGetStatusRsp, 0xff);
+                            &status_cmd->Retry, &aw, 0, ASPSTATE_WaitingForGetStatusRsp, 0xff);
                gbuf_freeb(mdata);
                return 0;
 
@@ -658,7 +668,7 @@ int asp_wput(gref, m)
                {
                struct atp_state *atp = (struct atp_state *)gref->info;
                if (atp->dflag)
-                       atp = atp->atp_msgq;
+                       atp = (struct atp_state *)atp->atp_msgq;
                                        
                if (gbuf_cont(mioc) == 0) {
                        asp_iocnak(gref, mioc, EINVAL);
@@ -774,15 +784,15 @@ asp_send_req(gref, mioc, dest, retry, awp, xo, state, bitmap)
 }
 
 /*
- * send tickle routine - funnelled version
+ * send tickle routine - locked version
  */
 StaticProc void
-asp_send_tickle_funnel(scb)
-       asp_scb_t *scb;
+asp_send_tickle_locked(scb)
+       void *scb;
 {
-        thread_funnel_set(network_flock, TRUE);
-       asp_send_tickle(scb);
-        thread_funnel_set(network_flock, FALSE);
+       atalk_lock();
+       asp_send_tickle((asp_scb_t *)scb);
+       atalk_unlock();
 }
 
 
@@ -810,7 +820,7 @@ asp_send_tickle(scb)
                dPrintf(D_M_ASP, D_L_WARNING,
                ("asp_send_tickle: ENOBUFS 0, loc=%d, rem=%d\n",
                        scb->loc_addr.socket,scb->rem_addr.socket));
-               timeout(asp_send_tickle_funnel, (void *)scb, 10);
+               timeout(asp_send_tickle_locked, (void *)scb, 10);
                return;
        }
        gbuf_wset(mioc,sizeof(ioc_t));
@@ -832,7 +842,7 @@ asp_send_tickle(scb)
                        ("asp_send_tickle: ENOBUFS 1, loc=%d, rem=%d\n",
                         scb->loc_addr.socket,scb->rem_addr.socket));
 
-               timeout(asp_send_tickle_funnel, (void *)scb, 10);
+               timeout(asp_send_tickle_locked, (void *)scb, 10);
                return;
        }
 }
@@ -893,14 +903,14 @@ asp_accept(scb, sess_scb, m)
 } /* asp_accept */
 
 /*
- * timer routine - funneled version
+ * timer routine - locked version
  */
-void asp_clock_funnel(arg)
+void asp_clock_locked(arg)
        void *arg;
 {
-        thread_funnel_set(network_flock, TRUE);
+       atalk_lock();
        asp_clock(arg);
-        thread_funnel_set(network_flock, FALSE);
+       atalk_unlock();
 }
 
 /*
@@ -929,7 +939,7 @@ void asp_clock(arg)
        ATENABLE(s, asptmo_lock);
 
        if (++scb_tmo_cnt == 0) scb_tmo_cnt++;
-       timeout(asp_clock_funnel, (void *)arg, (1<<SESS_TMO_RES)*TICKS_PER_SEC);
+       timeout(asp_clock_locked, (void *)arg, (1<<SESS_TMO_RES)*TICKS_PER_SEC);
         
 }
 
@@ -1103,7 +1113,7 @@ asp_ack_reply(gref, mioc)
                        if ((m = scb->sess_ioc) == 0) {
                                scb->sess_ioc = mdata;
                                if (scb->get_wait)
-                                       thread_wakeup(&scb->event);
+                                       wakeup(&scb->event);
                                else
                                        atalk_notify_sel(gref);
                        } else {
@@ -1316,7 +1326,7 @@ asp_ack_reply(gref, mioc)
                        gbuf_freem(mioc);
                        ATDISABLE(s, scb->lock);
                        if (scb->get_wait)
-                               thread_wakeup(&scb->event);
+                               wakeup(&scb->event);
                        else
                                atalk_notify_sel(gref);
                        ATENABLE(s, scb->lock);
@@ -1357,6 +1367,9 @@ asp_ack_reply(gref, mioc)
                        } else {
                                scb->rem_addr.node = scb->rem_node;
                                scb->rem_addr.socket = awp->func;
+                               /* bms:  need to set the reply_socket for client side too.
+                               This makes ALO atten replies sent by the client work. */
+                               scb->reply_socket = scb->rem_addr.socket;
                                scb->sess_id = awp->param1;
                                gbuf_freeb(mx);
                                atalk_putnext(gref, mioc);
@@ -1517,7 +1530,7 @@ asp_nak_reply(gref, mioc)
 
                        /* last remaining use of MSG_ERROR */
                        gbuf_set_type(mioc, MSG_ERROR);
-                       *gbuf_rptr(mioc) = (u_char)EPROTO;
+                       *gbuf_rptr(mioc) = (u_char)EPROTOTYPE;
                        gbuf_wset(mioc, 1);
                        if (gbuf_cont(mioc)) {
                                gbuf_freem(gbuf_cont(mioc));
@@ -1749,7 +1762,7 @@ asp_hangup(scb)
         */
        if (scb->rem_addr.node) {
                if (scb->get_wait) {
-                       thread_wakeup(&scb->event);
+                       wakeup(&scb->event);
                        ATENABLE(s, scb->lock);
                } else {
                        ATENABLE(s, scb->lock);
@@ -1878,7 +1891,7 @@ asp_putnext(gref, mproto)
                scb->snd_stop = 1;
 
        if (scb->get_wait) {
-               thread_wakeup(&scb->event);
+               wakeup(&scb->event);
                ATENABLE(s, scb->lock);
        } else if (mproto == scb->sess_ioc) {
                ATENABLE(s, scb->lock);
@@ -1894,265 +1907,330 @@ asp_putnext(gref, mproto)
 
 /* in ASPputmsg we expect:
 
-       ASPFUNC_CmdReply
-       ASPFUNC_Attention
-       ASPFUNC_Command
-       ASPFUNC_Write
-       ASPFUNC_WriteContinue
+    ASPFUNC_CmdReply
+    ASPFUNC_Attention
+    ASPFUNC_Command
+    ASPFUNC_Write
+    ASPFUNC_WriteContinue
+    
+    bms:  Make this callable from the kernel.
+    If mreq != NULL, then must be called from kernel space and the following apply:
+    1)  *mreq is data to be sent already in mbuf chains.
+    2)  datptr->len = size of data
 */
 
-int ASPputmsg(gref, ctlptr, datptr, flags, errp)
-       gref_t *gref;
-       strbuf_t *ctlptr;
-       strbuf_t *datptr;
-       int flags;
-       int *errp;
+int ASPputmsg(gref_t *gref, strbuf_t *ctlptr, strbuf_t *datptr, gbuf_t *mreq, int flags, int *errp)
 {
-       int s, i, err, len;
-       gbuf_t *mioc, *mdata, *mx;
-       ioc_t *iocbp;
-       strbuf_t ctlbuf;
-       strbuf_t datbuf;
-       asp_scb_t *scb;
-       int nbds, result, msize, Primitive;
-       unsigned char *wptr;
-       struct atp_set_default *sd;
-       at_ddp_t *ddp;
-       at_atp_t *atp;
-       struct atpBDS *atpBDS;
-       asp_word_t *awp;
-       union asp_primitives *primitives;
-       unsigned short tid;
-
-       if ((scb = (asp_scb_t *)gref->info) == 0) {
+    int s, i, err, len, offset, remain, size, copy_len;
+    gbuf_t *mioc, *mdata, *mx, *m0;
+    ioc_t *iocbp;
+    strbuf_t ctlbuf;
+    strbuf_t datbuf;
+    asp_scb_t *scb;
+    int nbds, result, msize, Primitive;
+    unsigned char *wptr;
+    struct atp_set_default *sd;
+    at_ddp_t *ddp;
+    at_atp_t *atp;
+    struct atpBDS *atpBDS;
+    asp_word_t *awp;
+    union asp_primitives *primitives;
+    unsigned short tid;
+    caddr_t            dataptr;
+    
+    if ((scb = (asp_scb_t *)gref->info) == 0) {
                dPrintf(D_M_ASP, D_L_ERROR,
                        ("ASPputmsg: stale handle=0x%x, pid=%d\n",
                        (u_int) gref, gref->pid));
 
-               *errp = EINVAL;
-               return -1;
-       }
-
-       if (scb->state == ASPSTATE_Close)
-               return 0;
-       if (scb->snd_stop) {
-               *errp = EAGAIN;
-               return -1;
-       }
-
-       /*
-        * copy in the control and data info
-        */
-       if ((err = copyin((caddr_t)ctlptr,
-                       (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0)
-               goto l_err;
-       if ((err = copyin((caddr_t)datptr,
-                       (caddr_t)&datbuf, sizeof(datbuf))) != 0)
-               goto l_err;
-
-       /*
-        * allocate buffer and copy in the control content
-        */
-       if (!(mioc = gbuf_alloc_wait(ctlbuf.len, TRUE))) {
-               /* error return should not be possible */
-               err = ENOBUFS;
-               goto l_err;
-       }
-       gbuf_set_type(mioc, MSG_IOCTL); /* for later, in ATP */
-       gbuf_wset(mioc, ctlbuf.len);
-       if ((err = copyin((caddr_t)ctlbuf.buf,
-                       (caddr_t)gbuf_rptr(mioc), ctlbuf.len)) != 0) {
-               gbuf_freem(mioc);
-               goto l_err;
-       }
+        *errp = EINVAL;
+        return -1;
+    }
+
+    if (scb->state == ASPSTATE_Close)
+        return 0;
+    if (scb->snd_stop) {
+        *errp = EAGAIN;
+        return -1;
+    }
+
+    /*
+     * copy in the control and data info
+     */
+     if (mreq != NULL) {
+        /* being called from kernel space */
+        bcopy (ctlptr, &ctlbuf, sizeof (strbuf_t));
+        bcopy (datptr, &datbuf, sizeof (strbuf_t));
+     } else {
+        /* being called from user space */
+        if ((err = copyin(CAST_USER_ADDR_T(ctlptr), (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0)
+            goto l_err;
+        if ((err = copyin(CAST_USER_ADDR_T(datptr), (caddr_t)&datbuf, sizeof(datbuf))) != 0)
+            goto l_err;
+     }
+
+    /*
+     * allocate buffer and copy in the control content
+     */
+    if (!(mioc = gbuf_alloc_wait(ctlbuf.len, TRUE))) {
+        /* error return should not be possible */
+        err = ENOBUFS;
+        goto l_err;
+    }
+    gbuf_set_type(mioc, MSG_IOCTL); /* for later, in ATP */
+    gbuf_wset(mioc, ctlbuf.len);
+    
+    if (mreq != NULL) {
+        /* being called from kernel space */
+        bcopy (ctlbuf.buf, gbuf_rptr(mioc), ctlbuf.len);
+    } else {
+        /* being called from user space */
+        if ((err = copyin(CAST_USER_ADDR_T(ctlbuf.buf), (caddr_t)gbuf_rptr(mioc), ctlbuf.len)) != 0) {
+            gbuf_freem(mioc);
+            goto l_err;
+        }
+    }
 
-       iocbp = (ioc_t *)gbuf_rptr(mioc);
-       primitives = (union asp_primitives *)gbuf_rptr(mioc);
-       Primitive = primitives->Primitive;
+    iocbp = (ioc_t *)gbuf_rptr(mioc);
+    primitives = (union asp_primitives *)gbuf_rptr(mioc);
+    Primitive = primitives->Primitive;
        dPrintf(D_M_ASP, D_L_INFO,
                ("ASPputmsg: %s\n", aspCmdStr(Primitive)));
 
-       /*
-        * allocate buffer and copy in the data content
-        */
-       len = (Primitive == ASPFUNC_CmdReply) ? 0 : aspCMDsize;
-       if (!(mdata = gbuf_alloc_wait(datbuf.len+len, TRUE))) {
-               /* error return should not be possible */
-               err = ENOBUFS;
-               gbuf_freem(mioc);
-               goto l_err;
-       }
-       gbuf_wset(mdata,(datbuf.len+len));
-       gbuf_cont(mioc) = mdata;
-       if ((err = copyin((caddr_t)datbuf.buf,
-                         (caddr_t)(gbuf_rptr(mdata)+len), datbuf.len)) != 0) {
-               gbuf_freem(mioc);
-               goto l_err;
-       }
-
-       switch (Primitive) {
-
-       case ASPFUNC_Command:
-       case ASPFUNC_Write:
-       case ASPFUNC_WriteContinue:
-       case ASPFUNC_Attention:
-               /*
-                * build the command/write/write_continue request
-                */
-               wptr = gbuf_rptr(mdata);
-               atpBDS = (struct atpBDS *)wptr;
-               wptr += atpBDSsize;
-               for (i=0; i < ATP_TRESP_MAX; i++) {
-                       *(unsigned long  *)atpBDS[i].bdsBuffAddr = 1;
-                       *(unsigned short *)atpBDS[i].bdsBuffSz = ATP_DATA_SIZE;
-               }
-               sd = (struct atp_set_default *)wptr;
-               wptr += sizeof(struct atp_set_default);
-               sd->def_retries = (scb->cmd_retry.retries == -1) ?
-                 ATP_INFINITE_RETRIES : scb->cmd_retry.retries;
-               sd->def_rate = scb->cmd_retry.interval*TICKS_PER_SEC;
-               sd->def_BDSlen = atpBDSsize;
-               ddp = (at_ddp_t *)wptr;
-               NET_ASSIGN(ddp->src_net, scb->loc_addr.net);
-               ddp->src_node = scb->loc_addr.node;
-               NET_ASSIGN(ddp->dst_net, scb->rem_addr.net);
-               ddp->dst_node = scb->rem_addr.node;
-               ddp->dst_socket = scb->rem_addr.socket;
-               UAS_ASSIGN(ddp->checksum, 0);
-               atp = ATP_ATP_HDR(wptr);
-               wptr += TOTAL_ATP_HDR_SIZE;
-               atp->xo = 1;
-               atp->xo_relt = 1;
-               atp->bitmap = 0xff;
-               awp = (asp_word_t *)atp->user_bytes;
-               awp->func = (unsigned char)Primitive;
-               awp->param1 = scb->sess_id;
-               awp->param2 = scb->snd_seq_num;
-               iocbp->ioc_private = (void *)scb;
-               iocbp->ioc_count = gbuf_len(mdata);
-               iocbp->ioc_rval = 0;
-               iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF;
-
-               /*
-                * send the command/write/write_continue/attention request
-                */
-               ATDISABLE(s, scb->lock);
-               switch (awp->func) {
-               case ASPFUNC_Command:
-                       scb->state = ASPSTATE_WaitingForCommandRsp;
-                       break;
-               case ASPFUNC_Write:
-                       scb->state = ASPSTATE_WaitingForWriteRsp;
-                       break;
-               case ASPFUNC_WriteContinue:
-                       scb->state = ASPSTATE_WaitingForWriteContinueRsp;
-                       awp->param2 = scb->wrt_seq_num;
-                       break;
-               case ASPFUNC_Attention:
-                       scb->state = ASPSTATE_WaitingForCommandRsp;
-                       atp->xo = 0;
-                       atp->xo_relt = 0;
-                       atp->bitmap = 0x01;
-                       gbuf_wdec(mdata,2);
-                       awp->param2 = *(unsigned short *)gbuf_wptr(mdata);
-                       break;
-               }
-               ATENABLE(s, scb->lock);
-               dPrintf(D_M_ASP,D_L_INFO,
-                       ("ASPputmsg: %s, loc=%d, rem=%x.%x.%d\n",
-                        (awp->func == ASPFUNC_Command ? "CommandReq" :
-                         awp->func == ASPFUNC_Write ? "WriteReq" :
-                         awp->func == ASPFUNC_WriteContinue ? "WriteContinue" :
-                         "AttentionReq"),scb->loc_addr.socket,
-                        NET_VALUE(ddp->dst_net),ddp->dst_node,ddp->dst_socket));
-               atp_send_req(gref, mioc);
-               return 0;
-
-       case ASPFUNC_CmdReply:
-
-               ATDISABLE(s, scb->lock);
-               if (scb->req_msgq) {
-                       mx = scb->req_msgq;
-                       scb->req_msgq = gbuf_next(mx);
-                       gbuf_next(mx) = 0;
-                       ATENABLE(s, scb->lock);
-                       asp_putnext(scb->gref, mx);
-               } else {
-                       scb->req_flag = 0;
-                       ATENABLE(s, scb->lock);
-               }
-               result = primitives->CmdReplyReq.CmdResult;
-               tid = primitives->CmdReplyReq.ReqRefNum;
-
-               /* Re-use the original mioc mbuf to send the response. */
-               gbuf_rinc(mioc,sizeof(void *));
-               gbuf_wset(mioc,0);
-               ddp = (at_ddp_t *)gbuf_wptr(mioc);
-               gbuf_winc(mioc,DDP_X_HDR_SIZE);
-               atp = (at_atp_t *)gbuf_wptr(mioc);
-               gbuf_winc(mioc,ATP_HDR_SIZE);
-               NET_ASSIGN(ddp->src_net, scb->loc_addr.net);
-               ddp->src_node = scb->loc_addr.node;
-               NET_ASSIGN(ddp->dst_net, scb->rem_addr.net);
-               ddp->dst_node = scb->rem_addr.node;
-               ddp->dst_socket = scb->reply_socket;
-               ddp->type = DDP_ATP;
-               UAS_ASSIGN(ddp->checksum, 0);
-               UAS_ASSIGN(atp->tid, tid);
-               if (scb->attn_flag && (tid == scb->attn_tid)) {
-                       scb->attn_flag = 0;
-                       atp->xo = 0;
-                       atp->xo_relt = 0;
-               } else {
-                       atp->xo = 1;
-                       atp->xo_relt = 1;
+    /*
+     * copy in the data content into multiple mbuf clusters if
+     * required.  ATP now expects reply data to be placed in
+     * standard clusters, not the large external clusters that
+     * were used previously.
+     */
+         
+    /* set offset for use by some commands */
+    offset = (Primitive == ASPFUNC_CmdReply) ? 0 : aspCMDsize;
+       size = 0;
+    if (mreq != NULL) {
+        /* The data from the in-kernel call for use by AFP is passed
+         * in as one large external cluster.  This needs to be copied
+         * to a chain of standard clusters.
+         */
+        remain = gbuf_len(mreq);
+        dataptr = mtod(mreq, caddr_t);
+    } else {
+       /* copyin from user space */
+       remain = datbuf.len; 
+       dataptr = (caddr_t)datbuf.buf;  
+    }  
+    
+    /* allocate first buffer */
+    if (!(mdata = gbuf_alloc_wait((remain + offset > MCLBYTES ? MCLBYTES : remain + offset), TRUE))) {
+        /* error return should not be possible */
+        err = ENOBUFS;
+        gbuf_freem(mioc);
+        goto l_err;
+    }
+    gbuf_wset(mdata, 0);               /* init length to zero */
+    gbuf_cont(mioc) = mdata;
+
+       while (remain) {
+               if (remain + offset > MCLBYTES)
+                       copy_len = MCLBYTES - offset;
+               else
+                       copy_len = remain;
+               remain -= copy_len;
+               if (mreq != NULL)
+                       bcopy (dataptr, (gbuf_rptr(mdata) + offset), copy_len);
+               else if ((err = copyin(CAST_USER_ADDR_T(dataptr), (caddr_t)(gbuf_rptr(mdata) + offset), copy_len)) != 0) {
+                       gbuf_freem(mioc);
+                       goto l_err;
                }
-               atpBDS = (struct atpBDS *)gbuf_wptr(mioc);
-               msize = mdata ? gbuf_msgsize(mdata) : 0;
-               for (nbds=0; (nbds < ATP_TRESP_MAX) && (msize > 0); nbds++) {
-                       len = msize < ATP_DATA_SIZE ? msize : ATP_DATA_SIZE;
-                       msize -= ATP_DATA_SIZE;
-                       *(long *)atpBDS[nbds].bdsUserData = 0;
-                       UAL_ASSIGN(atpBDS[nbds].bdsBuffAddr, 1);
-                       UAS_ASSIGN(atpBDS[nbds].bdsBuffSz, len);
+               gbuf_wset(mdata, (copy_len + offset));
+               size += copy_len + offset;
+               dataptr += copy_len;
+               offset = 0;
+               if (remain) {
+                       /* allocate the next mbuf */
+                       if ((gbuf_cont(mdata) = m_get((M_WAIT), MSG_DATA)) == 0) {
+                               err = ENOBUFS;
+                               gbuf_freem(mioc);
+                               goto l_err;
+                       }
+                       mdata = gbuf_cont(mdata);
+                       MCLGET(mdata, M_WAIT);
+                       if (!(mdata->m_flags & M_EXT)) {
+                               err = ENOBUFS;
+                               gbuf_freem(mioc);
+                               goto l_err;
+                       }
                }
-               UAS_ASSIGN(atpBDS[0].bdsDataSz, nbds);
-               *(long *)atpBDS[0].bdsUserData = (long)result;
-               *(long *)atp->user_bytes = (long)result;
-               gbuf_winc(mioc,atpBDSsize);
+       }
+       mdata = gbuf_cont(mioc);                        /* code further on down expects this to b e set */
+       mdata->m_pkthdr.len = size;                     /* set packet hdr len */
+
+       if (mreq != 0)
+               gbuf_freem(mreq);
+
+       switch (Primitive) {
+
+    case ASPFUNC_Command:
+    case ASPFUNC_Write:
+    case ASPFUNC_WriteContinue:
+    case ASPFUNC_Attention:
+        /*
+         * build the command/write/write_continue request
+         */
+        wptr = gbuf_rptr(mdata);
+        atpBDS = (struct atpBDS *)wptr;
+        wptr += atpBDSsize;
+        for (i=0; i < ATP_TRESP_MAX; i++) {
+            *(unsigned long  *)atpBDS[i].bdsBuffAddr = 1;
+            *(unsigned short *)atpBDS[i].bdsBuffSz = ATP_DATA_SIZE;
+        }
+        sd = (struct atp_set_default *)wptr;
+        wptr += sizeof(struct atp_set_default);
+        sd->def_retries = (scb->cmd_retry.retries == -1) ?
+          ATP_INFINITE_RETRIES : scb->cmd_retry.retries;
+        sd->def_rate = scb->cmd_retry.interval*TICKS_PER_SEC;
+        sd->def_BDSlen = atpBDSsize;
+        ddp = (at_ddp_t *)wptr;
+        NET_ASSIGN(ddp->src_net, scb->loc_addr.net);
+        ddp->src_node = scb->loc_addr.node;
+        NET_ASSIGN(ddp->dst_net, scb->rem_addr.net);
+        ddp->dst_node = scb->rem_addr.node;
+        ddp->dst_socket = scb->rem_addr.socket;
+        UAS_ASSIGN(ddp->checksum, 0);
+        atp = ATP_ATP_HDR(wptr);
+        wptr += TOTAL_ATP_HDR_SIZE;
+        atp->xo = 1;
+        atp->xo_relt = 1;
+        atp->bitmap = 0xff;
+        awp = (asp_word_t *)atp->user_bytes;
+        awp->func = (unsigned char)Primitive;
+        awp->param1 = scb->sess_id;
+        awp->param2 = scb->snd_seq_num;
+        iocbp->ioc_private = (void *)scb;
+        iocbp->ioc_count = gbuf_len(mdata);
+        iocbp->ioc_rval = 0;
+        iocbp->ioc_cmd = AT_ATP_ISSUE_REQUEST_DEF;
+
+        /*
+         * send the command/write/write_continue/attention request
+         */
+        ATDISABLE(s, scb->lock);
+        switch (awp->func) {
+        case ASPFUNC_Command:
+            scb->state = ASPSTATE_WaitingForCommandRsp;
+            break;
+        case ASPFUNC_Write:
+            scb->state = ASPSTATE_WaitingForWriteRsp;
+            break;
+        case ASPFUNC_WriteContinue:
+            scb->state = ASPSTATE_WaitingForWriteContinueRsp;
+            awp->param2 = scb->wrt_seq_num;
+            break;
+        case ASPFUNC_Attention:
+            scb->state = ASPSTATE_WaitingForCommandRsp;
+            atp->xo = 0;
+            atp->xo_relt = 0;
+            atp->bitmap = 0x01;
+            gbuf_wdec(mdata,2);
+            awp->param2 = *(unsigned short *)gbuf_wptr(mdata);
+            break;
+        }
+        ATENABLE(s, scb->lock);
+        dPrintf(D_M_ASP,D_L_INFO,
+            ("ASPputmsg: %s, loc=%d, rem=%x.%x.%d\n",
+             (awp->func == ASPFUNC_Command ? "CommandReq" :
+              awp->func == ASPFUNC_Write ? "WriteReq" :
+              awp->func == ASPFUNC_WriteContinue ? "WriteContinue" :
+              "AttentionReq"),scb->loc_addr.socket,
+             NET_VALUE(ddp->dst_net),ddp->dst_node,ddp->dst_socket));
+        atp_send_req(gref, mioc);
+        return 0;
+
+    case ASPFUNC_CmdReply:
+
+        ATDISABLE(s, scb->lock);
+        if (scb->req_msgq) {
+            mx = scb->req_msgq;
+            scb->req_msgq = gbuf_next(mx);
+            gbuf_next(mx) = 0;
+            ATENABLE(s, scb->lock);
+            asp_putnext(scb->gref, mx);
+        } else {
+            scb->req_flag = 0;
+            ATENABLE(s, scb->lock);
+        }
+        result = primitives->CmdReplyReq.CmdResult;
+        tid = primitives->CmdReplyReq.ReqRefNum;
+
+        /* Re-use the original mioc mbuf to send the response. */
+        gbuf_rinc(mioc,sizeof(void *));
+        gbuf_wset(mioc,0);
+        ddp = (at_ddp_t *)gbuf_wptr(mioc);
+        gbuf_winc(mioc,DDP_X_HDR_SIZE);
+        atp = (at_atp_t *)gbuf_wptr(mioc);
+        gbuf_winc(mioc,ATP_HDR_SIZE);
+        NET_ASSIGN(ddp->src_net, scb->loc_addr.net);
+        ddp->src_node = scb->loc_addr.node;
+        NET_ASSIGN(ddp->dst_net, scb->rem_addr.net);
+        ddp->dst_node = scb->rem_addr.node;
+        ddp->dst_socket = scb->reply_socket;
+        ddp->type = DDP_ATP;
+        UAS_ASSIGN(ddp->checksum, 0);
+        UAS_ASSIGN(atp->tid, tid);
+        if (scb->attn_flag && (tid == scb->attn_tid)) {
+           scb->attn_flag = 0;
+            atp->xo = 0;
+            atp->xo_relt = 0;
+        } else {
+            atp->xo = 1;
+            atp->xo_relt = 1;
+        }
+        /* setup the atpBDS struct - only the length field is used,
+         * except for the first one which contains the bds count in
+         * bdsDataSz.
+         */
+        atpBDS = (struct atpBDS *)gbuf_wptr(mioc);
+        msize = mdata ? gbuf_msgsize(mdata) : 0;
+               for (nbds=0; (nbds < ATP_TRESP_MAX) && (msize > 0); nbds++) {
+            len = msize < ATP_DATA_SIZE ? msize : ATP_DATA_SIZE;
+            msize -= ATP_DATA_SIZE;
+            *(long *)atpBDS[nbds].bdsUserData = 0;
+            UAL_ASSIGN(atpBDS[nbds].bdsBuffAddr, 1);
+            UAS_ASSIGN(atpBDS[nbds].bdsBuffSz, len);
+        }
+               UAS_ASSIGN(atpBDS[0].bdsDataSz, nbds);
+        *(long *)atpBDS[0].bdsUserData = (long)result;
+        *(long *)atp->user_bytes = (long)result;
+        gbuf_winc(mioc,atpBDSsize);
                dPrintf(D_M_ASP, D_L_INFO,
                        ("ASPputmsg: ATP CmdReplyReq, loc=%d, state=%s, msgsize = %d, result = %d, tid = %d\n",
                         scb->loc_addr.socket, aspStateStr(scb->state), 
                         (mdata ? gbuf_msgsize(mdata) : 0), result, tid));
-               atp_send_rsp(gref, mioc, TRUE);
-               return 0;
-       }
+        atp_send_rsp(gref, mioc, TRUE);
+        return 0;
+    }
 
-       /* Not an expected ASPFUNC */
-       gbuf_freem(mioc);
-       err = EOPNOTSUPP;
+    /* Not an expected ASPFUNC */
+    gbuf_freem(mioc);
+    err = EOPNOTSUPP;
 
 l_err:
-       *errp = err;
-       return -1;
+    *errp = err;
+    return -1;
 } /* ASPputmsg */
 
-int
-ASPgetmsg(gref, ctlptr, datptr, flags, errp)
-       gref_t *gref;
-       strbuf_t *ctlptr;
-       strbuf_t *datptr;
-       int *flags;
-       int *errp;
-{
-       int err, s, len, sum, rval;
-       gbuf_t *mproto, *mdata;
-       strbuf_t ctlbuf;
-       strbuf_t datbuf;
-       asp_scb_t *scb;
-       unsigned char get_wait;
 
-       if ((scb = (asp_scb_t *)gref->info) == 0) {
+/* bms:  make this callable from kernel.  reply date is passed back as a mbuf chain in *mreply  */
+int ASPgetmsg(gref_t *gref, strbuf_t *ctlptr, strbuf_t *datptr, gbuf_t **mreply, int *flags, int *errp)
+{
+    int err, s, len, sum, rval;
+    gbuf_t *mproto, *mdata;
+    strbuf_t ctlbuf;
+    strbuf_t datbuf;
+    asp_scb_t *scb;
+    unsigned char get_wait;
+
+    if ((scb = (asp_scb_t *)gref->info) == 0) {
                dPrintf(D_M_ASP, D_L_ERROR,
                        ("ASPgetmsg: stale handle=0x%x, pid=%d\n",
                        (u_int) gref, gref->pid));
@@ -2161,138 +2239,163 @@ ASPgetmsg(gref, ctlptr, datptr, flags, errp)
                return -1;
        }
 
-       ATDISABLE(s, scb->lock);
-       if (scb->state == ASPSTATE_Close) {
-               ATENABLE(s, scb->lock);
-               return 0;
-       }
-
-       /*
-        * get receive data
-        */
-       while ((mproto = scb->sess_ioc) == 0) {
-               scb->get_wait = 1;
-               err = tsleep(&scb->event, PSOCK | PCATCH, "aspgetmsg", 0);
-               if (err != 0) {
-                       scb->get_wait = 0;
-                       ATENABLE(s, scb->lock);
-                       *errp = err;
-                       return -1;
-               }
-               if (scb->state == ASPSTATE_Close) {
-                       scb->get_wait = 0;
-                       ATENABLE(s, scb->lock);
-                       return 0;
-               }
-       }
-       get_wait = scb->get_wait;
-       scb->get_wait = 0;
-       if ((ctlptr == 0) && (datptr == 0)) {
-               ATENABLE(s, scb->lock);
-               return 0;
-       }
-       scb->sess_ioc = gbuf_next(mproto);
-       mdata = gbuf_cont(mproto);
-       ATENABLE(s, scb->lock);
-
-       /* last remaining use of MSG_ERROR */
-       if (gbuf_type(mproto) == MSG_ERROR) {
-               err = (int)gbuf_rptr(mproto)[0];
-               goto l_err;
-       }
-
-       /*
-        * copy in the control and data info
-        */
-       if ((err = copyin((caddr_t)ctlptr,
-                       (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0)
-               goto l_err;
-       if ((err = copyin((caddr_t)datptr,
-                       (caddr_t)&datbuf, sizeof(datbuf))) != 0)
-               goto l_err;
-       if ((datbuf.maxlen < 0) || (datbuf.maxlen < gbuf_msgsize(mdata))) {
-               ATDISABLE(s, scb->lock);
-               gbuf_next(mproto) = scb->sess_ioc;
-               scb->sess_ioc = mproto;
-               ATENABLE(s, scb->lock);
-               return MOREDATA;
-       }
-
-       if (get_wait == 0) {
-               /*
-                * this is a hack to support the select() call.
-                * we're not supposed to dequeue messages in the Streams 
-                * head's read queue this way; but there is no better way.
-                */
-               ATDISABLE(s, scb->lock);
-               if (scb->sess_ioc == 0) {
-                       ATENABLE(s, scb->lock);
-               } else {
-                       ATENABLE(s, scb->lock);
-                       atalk_notify_sel(gref); 
-               }
-       }
-
-       /*
-        * copy out the control content and info
-        */
-       ctlbuf.len = gbuf_len(mproto);
-       if ((err = copyout((caddr_t)gbuf_rptr(mproto),
-                       (caddr_t)ctlbuf.buf, ctlbuf.len)) != 0)
-               goto l_err;
-       if ((err = copyout((caddr_t)&ctlbuf,
-                       (caddr_t)ctlptr, sizeof(ctlbuf))) != 0)
-               goto l_err;
-
-       /*
-        * copy out the data content and info
-        */
-       for (rval=0, sum=0; mdata && (rval == 0); mdata = gbuf_cont(mdata)) {
-               len = gbuf_len(mdata);
-         if (len) {
-               if ((len + sum) > datbuf.maxlen) {
-                       len = datbuf.maxlen - sum;
-                       rval = MOREDATA;
-               }
-               if ((err = copyout((caddr_t)gbuf_rptr(mdata),
-                               (caddr_t)&datbuf.buf[sum], len)) != 0)
-                       goto l_err;
-               sum += len;
-         }
-       }
-       datbuf.len = sum;
-       if ((err = copyout((caddr_t)&datbuf,
-                       (caddr_t)datptr, sizeof(datbuf))) != 0)
-               goto l_err;
-
-#ifdef APPLETALK_DEBUG
-       if (mproto == 0) 
-               kprintf("ASPgetmsg: null mproto!!!\n");
-#endif
-
-       gbuf_freem(mproto);
-
-       ATDISABLE(s, scb->lock);
-       if (scb->sess_ioc)
-               scb->rcv_cnt--;
-       else {
-               scb->rcv_cnt = 0;
-               scb->snd_stop = 0;
-       }
-       ATENABLE(s, scb->lock);
-       return rval;
+    ATDISABLE(s, scb->lock);
+    if (scb->state == ASPSTATE_Close) {
+        ATENABLE(s, scb->lock);
+        return 0;
+    }
+
+    /*
+     * get receive data
+     */
+    while ((mproto = scb->sess_ioc) == 0) {
+        scb->get_wait = 1;
+          lck_mtx_assert(atalk_mutex, LCK_MTX_ASSERT_OWNED);
+        err = msleep(&scb->event, atalk_mutex, PSOCK | PCATCH, "aspgetmsg", 0);
+        if (err != 0) {
+            scb->get_wait = 0;
+            ATENABLE(s, scb->lock);
+            *errp = err;
+            return -1;
+        }
+        if (scb->state == ASPSTATE_Close) {
+            scb->get_wait = 0;
+            ATENABLE(s, scb->lock);
+            return 0;
+        }
+    }
+    get_wait = scb->get_wait;
+    scb->get_wait = 0;
+    if ((ctlptr == 0) && (datptr == 0)) {
+        ATENABLE(s, scb->lock);
+        return 0;
+    }
+    scb->sess_ioc = gbuf_next(mproto);
+    mdata = gbuf_cont(mproto);
+    ATENABLE(s, scb->lock);
+
+    /* last remaining use of MSG_ERROR */
+    if (gbuf_type(mproto) == MSG_ERROR) {
+        err = (int)gbuf_rptr(mproto)[0];
+        goto l_err;
+    }
+
+    /*
+     * copy in the control and data info
+     */
+    if (mreply != NULL) {
+        /* called from kernel space */
+        bcopy (ctlptr, &ctlbuf, sizeof(ctlbuf));
+        bcopy (datptr, &datbuf, sizeof(datbuf));
+    } else {
+        /* called from user space */
+        if ((err = copyin(CAST_USER_ADDR_T(ctlptr),
+                (caddr_t)&ctlbuf, sizeof(ctlbuf))) != 0)
+            goto l_err;
+        if ((err = copyin(CAST_USER_ADDR_T(datptr),
+                (caddr_t)&datbuf, sizeof(datbuf))) != 0)
+            goto l_err;
+    }
+    if ((datbuf.maxlen < 0) || (datbuf.maxlen < gbuf_msgsize(mdata))) {
+        ATDISABLE(s, scb->lock);
+        gbuf_next(mproto) = scb->sess_ioc;
+        scb->sess_ioc = mproto;
+        ATENABLE(s, scb->lock);
+        return MOREDATA;
+    }
+
+    if (get_wait == 0) {
+        /*
+         * this is a hack to support the select() call.
+         * we're not supposed to dequeue messages in the Streams 
+         * head's read queue this way; but there is no better way.
+         */
+        ATDISABLE(s, scb->lock);
+        if (scb->sess_ioc == 0) {
+            ATENABLE(s, scb->lock);
+        } else {
+            ATENABLE(s, scb->lock);
+            atalk_notify_sel(gref); 
+        }
+    }
+
+    /*
+     * copy out the control content and info
+     */
+    ctlbuf.len = gbuf_len(mproto);
+
+    if (mreply != NULL) {
+        /* called from kernel space */
+        bcopy (gbuf_rptr(mproto), ctlbuf.buf, ctlbuf.len);
+        bcopy (&ctlbuf, ctlptr, sizeof(ctlbuf));
+    } else {
+        /* called from user space */
+        if ((err = copyout((caddr_t)gbuf_rptr(mproto),
+                CAST_USER_ADDR_T(ctlbuf.buf), ctlbuf.len)) != 0)
+            goto l_err;
+        if ((err = copyout((caddr_t)&ctlbuf,
+                CAST_USER_ADDR_T(ctlptr), sizeof(ctlbuf))) != 0)
+            goto l_err;
+    }
+
+    /*
+     * copy out the data content and info
+     */
+    for (rval = 0, sum = 0; mdata && (rval == 0); mdata = gbuf_cont(mdata)) 
+    {
+        len = gbuf_len(mdata);
+        if (len) {
+            if ((len + sum) > datbuf.maxlen) {
+                len = datbuf.maxlen - sum;
+                rval = MOREDATA;
+            }
+            
+            if (mreply == NULL) {
+                /* called from user space */
+                if ((err = copyout((caddr_t)gbuf_rptr(mdata), CAST_USER_ADDR_T(&datbuf.buf[sum]), len)) != 0)
+                    goto l_err;
+            }
+            sum += len;
+        }
+    }
+    datbuf.len = sum;
+    if (mreply != NULL) {
+        /* called from kernel space */
+        bcopy (&datbuf, datptr, sizeof(datbuf));
+    } else {
+        /* called from user space */
+        if ((err = copyout((caddr_t)&datbuf, CAST_USER_ADDR_T(datptr), sizeof(datbuf))) != 0)
+            goto l_err;
+    }
+    
+    if (mreply != NULL) {
+        /* called from kernel space */
+        /* return the reply data in mbufs, so dont free them.  
+        Just free the proto info */
+        mdata = gbuf_cont(mproto);
+        *mreply = mdata;
+        gbuf_cont(mproto) = NULL;
+        gbuf_freem(mproto);
+    } else {
+        /* called from user space */
+        gbuf_freem(mproto);
+    }
+
+    ATDISABLE(s, scb->lock);
+    if (scb->sess_ioc)
+        scb->rcv_cnt--;
+    else {
+        scb->rcv_cnt = 0;
+        scb->snd_stop = 0;
+    }
+    ATENABLE(s, scb->lock);
+    return rval;
 
 l_err:
-       dPrintf(D_M_ASP, D_L_ERROR,
-               ("ASPgetmsg: err=%d, loc=%d, rem=%x.%x.%d, state=%s\n",
-                err, scb->loc_addr.socket, 
-                scb->rem_addr.net,
-                scb->rem_addr.node, scb->rem_addr.socket,
-                aspStateStr(scb->state)));
-       ATDISABLE(s, scb->lock);
-       gbuf_next(mproto) = scb->sess_ioc;
-       scb->sess_ioc = mproto;
-       ATENABLE(s, scb->lock);
-       *errp = err;
-       return -1;
+    ATDISABLE(s, scb->lock);
+    gbuf_next(mproto) = scb->sess_ioc;
+    scb->sess_ioc = mproto;
+    ATENABLE(s, scb->lock);
+    *errp = err;
+    return -1;
 }