]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netat/atp_write.c
xnu-792.tar.gz
[apple/xnu.git] / bsd / netat / atp_write.c
index 4fea05d134bcba8f6192362b31623dc70203b0f7..865962ef6191bd94cac060d522aba137e66ee523 100644 (file)
@@ -38,6 +38,7 @@
 #include <sys/proc.h>
 #include <sys/filedesc.h>
 #include <sys/fcntl.h>
+#include <kern/locks.h>
 #include <sys/mbuf.h>
 #include <sys/ioctl.h>
 #include <sys/malloc.h>
@@ -67,7 +68,7 @@ static int loop_cnt; /* for debugging loops */
 static void atp_pack_bdsp(struct atp_trans *, struct atpBDS *);
 static int atp_unpack_bdsp(struct atp_state *, gbuf_t *, struct atp_rcb *, 
                           int, int);
-void atp_retry_req(), atp_trp_clock(), asp_clock(), asp_clock_funnel(), atp_trp_clock_funnel();;
+void atp_trp_clock(), asp_clock(), asp_clock_locked(), atp_trp_clock_locked();;
 
 extern struct atp_rcb_qhead atp_need_rel;
 extern int atp_inited;
@@ -82,6 +83,7 @@ extern gbuf_t *atp_resource_m;
 extern gref_t *atp_inputQ[];
 extern int atp_pidM[];
 extern at_ifaddr_t *ifID_home;
+extern lck_mtx_t * atalk_mutex;
 
 static struct atp_trans *trp_tmo_list;
 struct atp_trans *trp_tmo_rcb;
@@ -104,8 +106,8 @@ void atp_link()
 
 void atp_unlink()
 {
-       untimeout(asp_clock_funnel, (void *)&atp_inited);
-       untimeout(atp_trp_clock_funnel, (void *)&atp_inited);
+       untimeout(asp_clock_locked, (void *)&atp_inited);
+       untimeout(atp_trp_clock_locked, (void *)&atp_inited);
        atp_untimout(atp_rcb_timer, trp_tmo_rcb); 
        trp_tmo_list = 0;
 
@@ -452,11 +454,11 @@ void atp_send_replies(atp, rcbp)
      register struct atp_rcb   *rcbp;
 {       register gbuf_t *m;
        register int     i, len;
-       int              s_gen, s, cnt;
+       int              s_gen, s, cnt, err, offset, space;
        unsigned char *m0_rptr = NULL, *m0_wptr = NULL;
        register at_atp_t *athp;
        register struct atpBDS *bdsp;
-       register gbuf_t *m2, *m1, *m0, *m3;
+       register gbuf_t *m2, *m1, *m0, *mhdr;
        caddr_t lastPage;
        gbuf_t *mprev, *mlist = 0;
        at_socket src_socket = (at_socket)atp->atp_socket_no;
@@ -464,6 +466,7 @@ void atp_send_replies(atp, rcbp)
        struct   ddp_atp {
                 char    ddp_atp_hdr[TOTAL_ATP_HDR_SIZE];
        };
+       struct timeval timenow;
 
        ATDISABLE(s, atp->atp_lock);
        if (rcbp->rc_queue != atp) {
@@ -494,109 +497,69 @@ void atp_send_replies(atp, rcbp)
 
        m = rcbp->rc_xmt;
        m0 = gbuf_cont(m);
-       if (m0) {
-               m0_rptr = gbuf_rptr(m0);
-               m0_wptr = gbuf_wptr(m0);
-       }
        if (gbuf_len(m) > TOTAL_ATP_HDR_SIZE)
                bdsp = (struct atpBDS *)(AT_ATP_HDR(m)->data);
        else
                bdsp = 0;
-
+       offset = 0;
+       if (m0)
+               space = gbuf_msgsize(m0);
+       else
+         space = 0;
        for (i = 0; i < cnt; i++) {
-         if (rcbp->rc_snd[i] == 0) {
-               if ((len = UAS_VALUE(bdsp->bdsBuffSz)))
-                       gbuf_rinc(m0,len);
-
-         } else {
-               m2 = rc_xmt[i];
-               gbuf_rinc(m2,AT_WR_OFFSET);
-               gbuf_wset(m2,TOTAL_ATP_HDR_SIZE);
-               *(struct ddp_atp *)(gbuf_rptr(m2))= *(struct ddp_atp *)(gbuf_rptr(m));
-               athp = AT_ATP_HDR(m2);
-               ATP_CLEAR_CONTROL(athp);
-               athp->cmd = ATP_CMD_TRESP;
-               athp->bitmap = i;
-               if (i == (cnt - 1))
-                       athp->eom = 1; /* for the last fragment */
-               if (bdsp)
-                       UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
-
-               if (bdsp)
-                 if (len = UAS_VALUE(bdsp->bdsBuffSz)) { /* copy in data */
-                   if (m0 && gbuf_len(m0)) {
-                     if ((m1 = gbuf_dupb(m0)) == NULL) {
-                               for (i = 0; i < cnt; i++)
-                                       if (rc_xmt[i])
-                                               gbuf_freem(rc_xmt[i]);
-                               gbuf_rptr(m0) = m0_rptr;
-                               gbuf_wset(m0,(m0_wptr-m0_rptr));
-                               goto nothing_to_send;
+               if (rcbp->rc_snd[i] == 0) {
+                       if ((len = UAS_VALUE(bdsp->bdsBuffSz))) {
+                               offset += len;
+                               space -= len;
                        }
-                       gbuf_wset(m1,len);
-                       gbuf_rinc(m0,len);
-                       if ((len = gbuf_len(m0)) < 0) {
-                               gbuf_rdec(m0,len);
-                               gbuf_wdec(m1,len);
-                               if (!append_copy((struct mbuf *)m1, 
-                                                (struct mbuf *)gbuf_cont(m0), FALSE)) {
-                                 for (i = 0; i < cnt; i++)
-                                       if (rc_xmt[i])
-                                               gbuf_freem(rc_xmt[i]);
-                                 gbuf_rptr(m0) = m0_rptr;
-                                 gbuf_wset(m0,(m0_wptr-m0_rptr));
-                                 goto nothing_to_send;
+               } else {
+                       mhdr = rc_xmt[i];
+                       /* setup header fields */
+                       gbuf_rinc(mhdr,AT_WR_OFFSET);
+                       gbuf_wset(mhdr,TOTAL_ATP_HDR_SIZE);
+                       *(struct ddp_atp *)(gbuf_rptr(mhdr))= *(struct ddp_atp *)(gbuf_rptr(m));
+                       athp = AT_ATP_HDR(mhdr);
+                       ATP_CLEAR_CONTROL(athp);
+                       athp->cmd = ATP_CMD_TRESP;
+                       athp->bitmap = i;
+                       if (i == (cnt - 1))
+                               athp->eom = 1; /* for the last fragment */
+                       if (bdsp) {
+                               UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
+                               if ((len = UAS_VALUE(bdsp->bdsBuffSz)) && m0 != 0 && space > 0) {
+                                       if ((m1 = m_copym(m0, offset, len, M_DONTWAIT)) == 0) {
+                                               for (i = 0; i < cnt; i++)
+                                                       if (rc_xmt[i])
+                                                               gbuf_freem(rc_xmt[i]);
+                                               goto nothing_to_send;
+                                       }
+                                       offset += len;
+                                       space -= len;
+                                       gbuf_cont(mhdr) = m1;
                                }
-                       } else
-                               gbuf_cont(m1) = 0;
-                       gbuf_cont(m2) = m1;
+                       }       
                                
-                       /* temp fix for page boundary problem  - bug# 2703163 */
-                       lastPage = (caddr_t)((int)(gbuf_wptr(m1) - 1) & ~PAGE_MASK);                    /* 4k page of last byte */
-                       if (lastPage != (caddr_t)((int)(gbuf_rptr(m1)) & ~PAGE_MASK)) {                 /* 1st byte and last on same page ? */
-                               if ((m3 = gbuf_dupb(m1)) == NULL) {
-                                       for (i = 0; i < cnt; i++)
-                                               if (rc_xmt[i])
-                                                       gbuf_freem(rc_xmt[i]);
-                                       (gbuf_rptr(m0)) = m0_rptr;
-                                       gbuf_wset(m0, (m0_wptr - m0_rptr));
-                                       goto nothing_to_send;
-                               }
-                               (gbuf_rptr(m3)) = lastPage;                                             /* new mbuf starts at beginning of page */
-                               gbuf_wset(m3, (gbuf_wptr(m1) - lastPage));              /* len = remaining data crossing over page boundary */
-                               gbuf_wset(m1, (lastPage - (gbuf_rptr(m1))));    /* adjust len of m1 */
-                               (gbuf_cont(m1)) = m3;
-                               (gbuf_cont(m3)) = 0;
-                       }
-                 }
+                       AT_DDP_HDR(mhdr)->src_socket = src_socket;
+                       dPrintf(D_M_ATP_LOW, D_L_OUTPUT,
+                               ("atp_send_replies: %d, socket=%d, size=%d\n",
+                               i, atp->atp_socket_no, gbuf_msgsize(gbuf_cont(m2))));
+       
+                       if (mlist)
+                               gbuf_next(mprev) = mhdr;
+                       else
+                               mlist = mhdr;
+                       mprev = mhdr;
+       
+                       rcbp->rc_snd[i] = 0;
+                       rcbp->rc_not_sent_bitmap &= ~atp_mask[i];
+                       if (rcbp->rc_not_sent_bitmap == 0)
+                               break;
                }
-
-         AT_DDP_HDR(m2)->src_socket = src_socket;
-         dPrintf(D_M_ATP_LOW, D_L_OUTPUT,
-               ("atp_send_replies: %d, socket=%d, size=%d\n",
-               i, atp->atp_socket_no, gbuf_msgsize(gbuf_cont(m2))));
-
-         if (mlist)
-               gbuf_next(mprev) = m2;
-         else
-               mlist = m2;
-         mprev = m2;
-
-         rcbp->rc_snd[i] = 0;
-         rcbp->rc_not_sent_bitmap &= ~atp_mask[i];
-         if (rcbp->rc_not_sent_bitmap == 0)
-               break;
-         }
-         /*
-          * on to the next frag
-          */
-         bdsp++;
-       }
-       if (m0) {
-               gbuf_rptr(m0) = m0_rptr;
-               gbuf_wset(m0,(m0_wptr-m0_rptr));
+               /*
+                * on to the next frag
+                */
+               bdsp++;
        }
-
        if (mlist) {
                ATENABLE(s, atp->atp_lock);
                DDP_OUTPUT(mlist);
@@ -625,9 +588,10 @@ nothing_to_send:
         *      resources.
         */
        if (rcbp->rc_xo && rcbp->rc_state != RCB_RELEASED) {
+               getmicrouptime(&timenow);
                ATDISABLE(s_gen, atpgen_lock);
                if (rcbp->rc_timestamp == 0) {
-                       rcbp->rc_timestamp = time.tv_sec;
+                       rcbp->rc_timestamp = timenow.tv_sec;
                        if (rcbp->rc_timestamp == 0)
                                rcbp->rc_timestamp = 1;
                        ATP_Q_APPEND(atp_need_rel, rcbp, rc_tlist);
@@ -680,10 +644,10 @@ atp_pack_bdsp(trp, bdsp)
                                        if (len > bufsize)
                                                len = bufsize;
                                        copyout((caddr_t)gbuf_rptr(m), 
-                                               (caddr_t)&buf[tmp],
+                                               CAST_USER_ADDR_T(&buf[tmp]),
                                                len);
                                        bufsize -= len;
-                                       tmp =+ len;
+                                       tmp += len;
                                }
                                m = gbuf_cont(m);
                        }
@@ -703,6 +667,11 @@ atp_pack_bdsp(trp, bdsp)
 } /* atp_pack_bdsp */
 
 
+/* create an mbuf chain with mbuf packet headers for each ATP response packet
+ * to be sent.  m contains the DDP hdr, ATP hdr, and and array of atpBDS structs.  
+ * chained to m is an mbuf that contians the actual data pointed to by the atpBDS
+ * structs.
+ */
 static int
 atp_unpack_bdsp(atp, m, rcbp, cnt, wait)
        struct atp_state *atp;
@@ -711,17 +680,20 @@ atp_unpack_bdsp(atp, m, rcbp, cnt, wait)
     register int    cnt, wait;
 {
        register struct atpBDS *bdsp;
-       register gbuf_t        *m2, *m1, *m0, *m3;
-       caddr_t lastPage;
-        register at_atp_t        *athp;
-       register int  i, len, s_gen;
-       at_socket src_socket;
-       struct   ddp_atp {
+       register         gbuf_t        *m2, *m1, *m0, *mhdr;
+       caddr_t         lastPage;
+    at_atp_t    *athp;
+       int             i, len, s_gen;
+       at_socket       src_socket;
+       
+       struct ddp_atp {
                 char    ddp_atp_hdr[TOTAL_ATP_HDR_SIZE];
        };
-       gbuf_t *mprev, *mlist = 0;
-       gbuf_t *rc_xmt[ATP_TRESP_MAX];
-       unsigned char *m0_rptr, *m0_wptr;
+       gbuf_t                  *mprev, *mlist = 0;
+       gbuf_t                  *rc_xmt[ATP_TRESP_MAX];
+       unsigned char   *m0_rptr, *m0_wptr;
+       int                             err, offset, space;
+       struct timeval timenow;
 
        /*
         * get the user data structure pointer
@@ -787,109 +759,79 @@ atp_unpack_bdsp(atp, m, rcbp, cnt, wait)
                goto l_send;
        }
 
+       /* create an array of mbuf packet headers for the packets to be sent
+        * to contain the atp and ddp headers with room at the front for the
+        * datalink header.
+        */
        for (i = 0; i < cnt; i++) {
                /* all hdrs, packet data and dst addr storage */
                if ((rc_xmt[i] = 
-                    gbuf_alloc_wait(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE,
-                                    wait)) == NULL) {
-                       for (cnt = 0; cnt < i; cnt++)
-                               if (rc_xmt[cnt])
-                                       gbuf_freeb(rc_xmt[cnt]);
-                       return 0;
+                    gbuf_alloc_wait(AT_WR_OFFSET+TOTAL_ATP_HDR_SIZE, wait)) == NULL) {
+                               for (cnt = 0; cnt < i; cnt++)
+                                       if (rc_xmt[cnt])
+                                               gbuf_freeb(rc_xmt[cnt]);
+                               return 0;
                }
        }
-       if (m0) {
-               m0_rptr = gbuf_rptr(m0);
-               m0_wptr = gbuf_wptr(m0);
-       }
 
-       for (i = 0; i < cnt; i++) {
-               m2 = rc_xmt[i];
-               gbuf_rinc(m2,AT_WR_OFFSET);
-               gbuf_wset(m2,TOTAL_ATP_HDR_SIZE);
-               *(struct ddp_atp *)(gbuf_rptr(m2))= *(struct ddp_atp *)(gbuf_rptr(m));
-               athp = AT_ATP_HDR(m2);
+       /* run through the atpBDS structs and create an mbuf for the data
+        * portion of each packet to be sent.  these get chained to the mbufs
+        * containing the ATP and DDP headers.  this code assumes that no ATP
+        * packet is contained in more than 2 mbufs (e.i crosses mbuf boundary
+        * no more than one time).
+        */
+       offset = 0;
+       if (m0)
+               space = gbuf_msgsize(m0);
+       for (i = 0; i < cnt; i++) {                     /* for each hdr mbuf */
+           mhdr = rc_xmt[i];
+           /* setup header fields */
+               gbuf_rinc(mhdr,AT_WR_OFFSET);
+               gbuf_wset(mhdr,TOTAL_ATP_HDR_SIZE);
+               *(struct ddp_atp *)(gbuf_rptr(mhdr))= *(struct ddp_atp *)(gbuf_rptr(m));
+               athp = AT_ATP_HDR(mhdr);
                ATP_CLEAR_CONTROL(athp);
                athp->cmd = ATP_CMD_TRESP;
                athp->bitmap = i;
                if (i == (cnt - 1))
                        athp->eom = 1; /* for the last fragment */
                UAL_UAL(athp->user_bytes, bdsp->bdsUserData);
-
-               if ((len = UAS_VALUE(bdsp->bdsBuffSz))) { /* copy in data */
-                 if (m0 && gbuf_len(m0)) {
-                       if ((m1 = gbuf_dupb_wait(m0, wait)) == NULL) {
+               
+               if ((len = UAS_VALUE(bdsp->bdsBuffSz)) != 0  && m0 != 0 && space > 0) {         
+                       if ((m1 = m_copym(m0, offset, len, wait)) == 0) {
                                for (i = 0; i < cnt; i++)
                                        if (rc_xmt[i])
                                                gbuf_freem(rc_xmt[i]);
-                               gbuf_rptr(m0) = m0_rptr;
-                               gbuf_wset(m0,(m0_wptr-m0_rptr));
                                return 0;
                        }
-                       gbuf_wset(m1,len); /* *** m1 is first len bytes of m0? *** */
-                       gbuf_rinc(m0,len);
-                       if ((len = gbuf_len(m0)) < 0) {
-                               gbuf_rdec(m0,len);
-                               gbuf_wdec(m1,len);
-                               if (!append_copy((struct mbuf *)m1, 
-                                                (struct mbuf *)gbuf_cont(m0), wait)) {
-                                 for (i = 0; i < cnt; i++)
-                                       if (rc_xmt[i])
-                                               gbuf_freem(rc_xmt[i]);
-                                 gbuf_rptr(m0) = m0_rptr;
-                                 gbuf_wset(m0,(m0_wptr-m0_rptr));
-                                 return 0;
-                               }
-                       } else
-                               gbuf_cont(m1) = 0;
-                       gbuf_cont(m2) = m1;
-                       
-                       /* temp fix for page boundary problem  - bug# 2703163 */
-                       lastPage = (caddr_t)((int)(gbuf_wptr(m1) - 1) & ~PAGE_MASK);                    /* 4k page of last byte */
-                       if (lastPage != (caddr_t)((int)(gbuf_rptr(m1)) & ~PAGE_MASK)) {                 /* 1st byte and last on same page ? */
-                               if ((m3 = gbuf_dupb_wait(m1, wait)) == NULL) {
-                                       for (i = 0; i < cnt; i++)
-                                               if (rc_xmt[i])
-                                                       gbuf_freem(rc_xmt[i]);
-                                       (gbuf_rptr(m0)) = m0_rptr;
-                                       gbuf_wset(m0, (m0_wptr - m0_rptr));
-                                       return 0;
-                               }
-                               (gbuf_rptr(m3)) = lastPage;                                             /* new mbuf starts at beginning of page */
-                               gbuf_wset(m3, (gbuf_wptr(m1) - lastPage));              /* len = remaining data crossing over page boundary */
-                               gbuf_wset(m1, (lastPage - (gbuf_rptr(m1))));            /* adjust len of m1 */
-                               (gbuf_cont(m1)) = m3;
-                               (gbuf_cont(m3)) = 0;
-                       }
-                 }
+                       gbuf_cont(mhdr) = m1;
+                       space -= len;
+                       offset += len;
                }
-
-               AT_DDP_HDR(m2)->src_socket = src_socket;
+                               
+               AT_DDP_HDR(mhdr)->src_socket = src_socket;
                dPrintf(D_M_ATP_LOW,D_L_INFO,
                        ("atp_unpack_bdsp %d, socket=%d, size=%d, cnt=%d\n",
-                       i,atp->atp_socket_no,gbuf_msgsize(gbuf_cont(m2)),cnt));
+                       i,atp->atp_socket_no,gbuf_msgsize(gbuf_cont(mhdr)),cnt));
                if (mlist)
-                       gbuf_next(mprev) = m2;
+                       gbuf_next(mprev) = mhdr;
                else
-                       mlist = m2;
-               mprev = m2;
+                       mlist = mhdr;
+               mprev = mhdr;
                /*
                 * on to the next frag
                 */
                bdsp++;
        }
-       if (m0) {
-               gbuf_rptr(m0) = m0_rptr;
-               gbuf_wset(m0,(m0_wptr-m0_rptr));
-       }
        /*
         * send the message
         */
 l_send:
        if (rcbp->rc_xo) {
+               getmicrouptime(&timenow);
                ATDISABLE(s_gen, atpgen_lock);
                if (rcbp->rc_timestamp == 0) {
-                       if ((rcbp->rc_timestamp = time.tv_sec) == 0)
+                       if ((rcbp->rc_timestamp = timenow.tv_sec) == 0)
                                rcbp->rc_timestamp = 1;
                        ATP_Q_APPEND(atp_need_rel, rcbp, rc_tlist);
                }
@@ -898,6 +840,7 @@ l_send:
 
        DDP_OUTPUT(mlist);
        return 0;
+
 } /* atp_unpack_bdsp */
 
 #define ATP_SOCKET_LAST  (DDP_SOCKET_LAST-6)
@@ -1183,12 +1126,12 @@ atp_untimout(func, trp)
 }
 
 void
-atp_trp_clock_funnel(arg)
+atp_trp_clock_locked(arg)
        void *arg;
 {
-       thread_funnel_set(network_flock, TRUE);
+       atalk_lock();
        atp_trp_clock(arg);
-       thread_funnel_set(network_flock, FALSE);
+       atalk_unlock();
 }
 
 void
@@ -1214,7 +1157,7 @@ atp_trp_clock(arg)
        }
        ATENABLE(s, atptmo_lock);
 
-       timeout(atp_trp_clock_funnel, (void *)arg, (1<<5));
+       timeout(atp_trp_clock_locked, (void *)arg, (1<<5));
 }
 
 void
@@ -1322,20 +1265,20 @@ l_retry:
        }
 } /* atp_send_req */
 
-void atp_retry_req(m)
-       gbuf_t *m;
+void atp_retry_req(arg)
+       void *arg;
 {
+       gbuf_t *m = (gbuf_t *)arg;
        gref_t *gref;
-       boolean_t       funnel_state;
 
-       funnel_state = thread_funnel_set(network_flock, TRUE);
+       atalk_lock();
 
        gref = (gref_t *)((ioc_t *)gbuf_rptr(m))->ioc_private;
        if (gref->info) {
                ((asp_scb_t *)gref->info)->stat_msg = 0;
                atp_send_req(gref, m);
        }
-       (void) thread_funnel_set(network_flock, FALSE);
+       atalk_unlock();
 }
 
 void atp_send_rsp(gref, m, wait)
@@ -1436,7 +1379,7 @@ int asp_pack_bdsp(trp, xm)
                gbuf_rinc(m, ATP_HDR_SIZE);
 
                if (UAL_VALUE(bdsp->bdsBuffAddr)) {
-                       short tmp;
+                       short tmp = 0;
 
                        /* user expects data back */
                        m = gbuf_strip(m);
@@ -1506,24 +1449,31 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
        gbuf_t *m2, *m, *mioc;
        char bds[atpBDSsize];
 
-       if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
+       if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
                return -1;
 
        if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
                        || (atp->atp_flags & ATP_CLOSING)) {
                dPrintf(D_M_ATP, D_L_ERROR, ("ATPsndreq: stale handle=0x%x, pid=%d\n",
                        (u_int) gref, gref->pid));
-
+               file_drop(fd);
                *err = EINVAL;
                return -1;
        }
 
+
        while ((mioc = gbuf_alloc(sizeof(ioc_t), PRI_MED)) == 0) {
+               struct timespec ts;
+               /* the vaue of 10n terms of hz is 100ms */
+               ts.tv_sec = 0;
+               ts.tv_nsec = 100 *1000 * NSEC_PER_USEC;
+
                ATDISABLE(s, atp->atp_delay_lock);
-               rc = tsleep(&atp->atp_delay_event, PSOCK | PCATCH, "atpmioc", 10);
+               rc = msleep(&atp->atp_delay_event, atalk_mutex, PSOCK | PCATCH, "atpmioc", &ts);
                ATENABLE(s, atp->atp_delay_lock);
                if (rc != 0) {
                        *err = rc;
+                       file_drop(fd);
                        return -1;
                }
                
@@ -1531,21 +1481,28 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
        gbuf_wset(mioc,sizeof(ioc_t));
        len -= atpBDSsize;
        while ((m2 = gbuf_alloc(len, PRI_MED)) == 0) {
+        struct timespec ts;
+        /* the vaue of 10n terms of hz is 100ms */
+        ts.tv_sec = 0;
+        ts.tv_nsec = 100 *1000 * NSEC_PER_USEC;
+
                ATDISABLE(s, atp->atp_delay_lock);
-               rc = tsleep(&atp->atp_delay_event, PSOCK | PCATCH, "atpm2", 10);
+               rc = msleep(&atp->atp_delay_event, atalk_mutex, PSOCK | PCATCH, "atpm2", &ts);
                ATENABLE(s, atp->atp_delay_lock);
                if (rc != 0) {
                        gbuf_freeb(mioc);
+                       file_drop(fd);
                        *err = rc;
                        return -1;
                }
        }
        gbuf_wset(m2, len);
        gbuf_cont(mioc) = m2;
-       if (((*err = copyin((caddr_t)buf, (caddr_t)bds, atpBDSsize)) != 0)
-               || ((*err = copyin((caddr_t)&buf[atpBDSsize],
+       if (((*err = copyin(CAST_USER_ADDR_T(buf), (caddr_t)bds, atpBDSsize)) != 0)
+               || ((*err = copyin(CAST_USER_ADDR_T(&buf[atpBDSsize]),
                        (caddr_t)gbuf_rptr(m2), len)) != 0)) {
                gbuf_freem(mioc);
+               file_drop(fd);
                return -1;
        }
        gbuf_set_type(mioc, MSG_IOCTL);
@@ -1567,11 +1524,17 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
         * allocate and set up the transaction record
         */
        while ((trp = atp_trans_alloc(atp)) == 0) {
+        struct timespec ts;
+        /* the vaue of 10n terms of hz is 100ms */
+        ts.tv_sec = 0;
+        ts.tv_nsec = 100 *1000 * NSEC_PER_USEC;
+
                ATDISABLE(s, atp->atp_delay_lock);
-               rc = tsleep(&atp->atp_delay_event, PSOCK | PCATCH, "atptrp", 10);
+               rc = msleep(&atp->atp_delay_event, atalk_mutex, PSOCK | PCATCH, "atptrp", &ts);
                ATENABLE(s, atp->atp_delay_lock);
                if (rc != 0) {
                        gbuf_freem(mioc);
+                       file_drop(fd);
                        *err = rc;
                        return -1;
                }
@@ -1634,8 +1597,10 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
        if (m)
                DDP_OUTPUT(m);
 
-       if (nowait)
+       if (nowait) {
+               file_drop(fd);
                return (int)tid;
+       }
 
        /*
         * wait for the transaction to complete
@@ -1644,10 +1609,11 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
        while ((trp->tr_state != TRANS_DONE) && (trp->tr_state != TRANS_FAILED) &&
                                (trp->tr_state != TRANS_ABORTING)) {
                trp->tr_rsp_wait = 1;
-               rc = tsleep(&trp->tr_event, PSOCK | PCATCH, "atpsndreq", 0);
+               rc = msleep(&trp->tr_event, atalk_mutex, PSOCK | PCATCH, "atpsndreq", 0);
                if (rc != 0) {
                        trp->tr_rsp_wait = 0;
                        ATENABLE(s, trp->tr_lock);
+                       file_drop(fd);
                        *err = rc;
                        return -1;
                }
@@ -1661,6 +1627,7 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
                 * transaction timed out, return error
                 */
                atp_free(trp);
+               file_drop(fd);
                *err = ETIMEDOUT;
                return -1;
        }
@@ -1668,18 +1635,27 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
        /*
         * copy out the recv data
         */
-       atp_pack_bdsp(trp, bds);
+       atp_pack_bdsp(trp, (struct atpBDS *)bds);
 
        /*
         * copyout the result info
         */
-       copyout((caddr_t)bds, (caddr_t)buf, atpBDSsize);
+       copyout((caddr_t)bds, CAST_USER_ADDR_T(buf), atpBDSsize);
 
        atp_free(trp);
+       file_drop(fd);
 
        return (int)tid;
 } /* _ATPsndreq */
 
+
+/*     entry point for ATP send response.  respbuf contains a DDP hdr,
+ *     ATP hdr, and atpBDS array.  The bdsDataSz field of the first atpBDS
+ *     struct contains the number of atpBDS structs in the array. resplen
+ *     contains the len of the data in respbuf and datalen contains the
+ *     len of the data buffer holding the response packets which the atpBDS
+ *     struct entries point to.
+ */
 int
 _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
        int fd;
@@ -1689,17 +1665,20 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
        int *err;
        void *proc;
 {
-       gref_t *gref;
-       int s, rc;
-       long bufaddr;
-       gbuf_t *m, *mdata;
-       register short len;
-       register int size;
-       register struct atp_state *atp;
-       register struct atpBDS *bdsp;
-       register char *buf;
+       gref_t          *gref;
+       int             s, rc;
+       long            bufaddr;
+       gbuf_t          *m, *mdata;
+       short           space;
+       int             size;
+       struct atp_state *atp;
+       struct atpBDS *bdsp;
+       u_int16_t       *bufsz;
+       char            *buf;
+       int                     bds_cnt, count, len;
+       caddr_t         dataptr;
 
-       if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
+       if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
                return -1;
 
        if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
@@ -1707,6 +1686,7 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
                dPrintf(D_M_ATP, D_L_ERROR, ("ATPsndrsp: stale handle=0x%x, pid=%d\n",
                        (u_int) gref, gref->pid));
 
+               file_drop(fd);
                *err = EINVAL;
                return -1;
        }
@@ -1716,44 +1696,88 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
         */
        if ((m = gbuf_alloc_wait(resplen, TRUE)) == 0) {
                *err = ENOMEM;
+               file_drop(fd);
                return -1;
        }
-       if ((*err = copyin((caddr_t)respbuff, (caddr_t)gbuf_rptr(m), resplen)) != 0) {
+       if ((*err = copyin(CAST_USER_ADDR_T(respbuff), (caddr_t)gbuf_rptr(m), resplen)) != 0) {
                gbuf_freeb(m);
+               file_drop(fd);
                return -1;
        }
        gbuf_wset(m,resplen);
        ((at_ddp_t *)gbuf_rptr(m))->src_node = 0;
        bdsp = (struct atpBDS *)(gbuf_rptr(m) + TOTAL_ATP_HDR_SIZE);
-       if ((resplen == TOTAL_ATP_HDR_SIZE) || ((len = UAS_VALUE(bdsp->bdsDataSz)) == 1))
-               len = 0;
-       else
-               len = 16 * sizeof(gbuf_t);
 
        /*
-        * allocate buffer and copy in the response data
+        * allocate buffers and copy in the response data.
+        * note that only the size field of the atpBDS field
+        * is used internally in the kernel.
         */
-       if ((mdata = gbuf_alloc_wait(datalen+len, TRUE)) == 0) {
-               gbuf_freem(m);
+       bds_cnt = get_bds_entries(m);           /* count of # entries */
+       /* check correctness of parameters */
+       if (bds_cnt > ATP_TRESP_MAX) {
+           gbuf_freem(m);
+               *err = EINVAL;
+               file_drop(fd);
+               return -1;
+       }
+       
+       for (size = 0, count = 0; count < bds_cnt; count++) {
+               size += UAS_VALUE(bdsp[count].bdsBuffSz);
+       }
+       if (size > datalen) {                           
+           gbuf_freem(m);
+               *err = EINVAL;
+               file_drop(fd);
+               return -1;
+       }
+       
+       /* get the first mbuf */
+       if ((mdata = gbuf_alloc_wait((space = (size > MCLBYTES ? MCLBYTES : size)), TRUE)) == 0) {
+           gbuf_freem(m);
+               file_drop(fd);
                *err = ENOMEM;
                return -1;
        }
        gbuf_cont(m) = mdata;
-       for (size=0; bdsp < (struct atpBDS *)gbuf_wptr(m); bdsp++) {
-               if ((bufaddr = UAL_VALUE(bdsp->bdsBuffAddr)) != 0) {
-                       len = UAS_VALUE(bdsp->bdsBuffSz);
-                       buf = (char *)bufaddr;
-                       if ((*err = copyin((caddr_t)buf,
-                                       (caddr_t)&gbuf_rptr(mdata)[size], len)) != 0) {
+       dataptr = mtod(mdata, caddr_t);
+       for (count = 0; count < bds_cnt; bdsp++, count++) {
+               if ((bufaddr = UAL_VALUE(bdsp->bdsBuffAddr)) != 0 && 
+                               (len = UAS_VALUE(bdsp->bdsBuffSz)) != 0) {
+                       if (len > space) {                                                                                      /* enough room ? */
+                               gbuf_wset(mdata, dataptr - mtod(mdata, caddr_t));               /* set len of last mbuf */
+                               /* allocate the next mbuf */
+                               if ((gbuf_cont(mdata) = m_get((M_WAIT), MSG_DATA)) == 0) {
+                                       gbuf_freem(m);
+                                       file_drop(fd);
+                                       *err = ENOMEM;
+                                       return -1;
+                               }
+                               mdata = gbuf_cont(mdata);       
+                               MCLGET(mdata, M_WAIT);
+                               if (!(mdata->m_flags & M_EXT)) {
+                                       m_freem(m);
+                                       file_drop(fd);
+                                       return(NULL);
+                               }
+                               dataptr = mtod(mdata, caddr_t);
+                               space = MCLBYTES;
+                       }
+                       /* do the copyin */
+                       if ((*err = copyin(CAST_USER_ADDR_T(bufaddr), dataptr, len)) != 0) {
                                gbuf_freem(m);
+                               file_drop(fd);
                                return -1;
                        }
-                       size += len;
+                       dataptr += len;
+                       space -= len;
                }
        }
-       gbuf_wset(mdata,size);
+       gbuf_wset(mdata, dataptr - mtod(mdata, caddr_t));               /* set len of last mbuf */
+       gbuf_cont(m)->m_pkthdr.len = size;                                              /* set packet hdr len */
 
        atp_send_rsp(gref, m, TRUE);
+       file_drop(fd);
        return 0;
 }
 
@@ -1771,13 +1795,14 @@ _ATPgetreq(fd, buf, buflen, err, proc)
        register gbuf_t *m, *m_head;
        int s, size, len;
 
-       if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
+       if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
                return -1;
 
        if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
                        || (atp->atp_flags & ATP_CLOSING)) {
                dPrintf(D_M_ATP, D_L_ERROR, ("ATPgetreq: stale handle=0x%x, pid=%d\n",
                        (u_int) gref, gref->pid));
+               file_drop(fd);
                *err = EINVAL;
                return -1;
        }
@@ -1808,17 +1833,19 @@ _ATPgetreq(fd, buf, buflen, err, proc)
                for (size=0, m=m_head; m; m = gbuf_cont(m)) {
                        if ((len = gbuf_len(m)) > buflen)
                                len = buflen;
-                       copyout((caddr_t)gbuf_rptr(m), (caddr_t)&buf[size], len);
+                       copyout((caddr_t)gbuf_rptr(m), CAST_USER_ADDR_T(&buf[size]), len);
                        size += len;
                        if ((buflen -= len) == 0)
                                break;
                }
                gbuf_freem(m_head);
 
+               file_drop(fd);
                return size;
        }
        ATENABLE(s, atp->atp_lock);
 
+       file_drop(fd);
        return -1;
 }
 
@@ -1835,13 +1862,14 @@ _ATPgetrsp(fd, bdsp, err, proc)
        int s, tid;
        char bds[atpBDSsize];
 
-       if ((*err = atalk_getref(0, fd, &gref, proc)) != 0)
+       if ((*err = atalk_getref(0, fd, &gref, proc, 1)) != 0)
                return -1;
 
        if ((gref == 0) || ((atp = (struct atp_state *)gref->info) == 0)
                        || (atp->atp_flags & ATP_CLOSING)) {
                dPrintf(D_M_ATP, D_L_ERROR, ("ATPgetrsp: stale handle=0x%x, pid=%d\n",
                        (u_int) gref, gref->pid));
+               file_drop(fd);
                *err = EINVAL;
                return -1;
        }
@@ -1855,13 +1883,16 @@ _ATPgetrsp(fd, bdsp, err, proc)
                switch (trp->tr_state) {
                case TRANS_DONE:
                ATENABLE(s, atp->atp_lock);
-                       if ((*err = copyin((caddr_t)bdsp,
-                                       (caddr_t)bds, sizeof(bds))) != 0)
+                       if ((*err = copyin(CAST_USER_ADDR_T(bdsp),
+                                       (caddr_t)bds, sizeof(bds))) != 0) {
+                               file_drop(fd);
                                return -1;
-                       atp_pack_bdsp(trp, bds);
+                       }
+                       atp_pack_bdsp(trp, (struct atpBDS *)bds);
                        tid = (int)trp->tr_tid;
                        atp_free(trp);
-                       copyout((caddr_t)bds, (caddr_t)bdsp, sizeof(bds));
+                       copyout((caddr_t)bds, CAST_USER_ADDR_T(bdsp), sizeof(bds));
+                       file_drop(fd);
                        return tid;
 
                case TRANS_FAILED:
@@ -1870,6 +1901,7 @@ _ATPgetrsp(fd, bdsp, err, proc)
                         */
                ATENABLE(s, atp->atp_lock);
                        atp_free(trp);
+                       file_drop(fd);
                        *err = ETIMEDOUT;
                        return -1;
 
@@ -1879,6 +1911,7 @@ _ATPgetrsp(fd, bdsp, err, proc)
        }
        ATENABLE(s, atp->atp_lock);
 
+       file_drop(fd);
        *err = EINVAL;
        return -1;
 }