]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/netat/atp_write.c
xnu-792.17.14.tar.gz
[apple/xnu.git] / bsd / netat / atp_write.c
index 1c3e4df3f8ff2cce26a9cfa00ad380af4f2bda85..34d18be4bc998019682cf421d7afb5d61d1123e3 100644 (file)
@@ -1,16 +1,19 @@
 /*
  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
  *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * Copyright (c) 1999-2003 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. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
+ * 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
@@ -20,7 +23,7 @@
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * 
- * @APPLE_LICENSE_HEADER_END@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
  *     Copyright (c) 1996-1998 Apple Computer, Inc.
@@ -41,6 +44,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,10 +71,10 @@ static int loop_cnt; /* for debugging loops */
   } \
 }
 
-static void atp_pack_bdsp(struct atp_trans *, struct atpBDS *);
+static int 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;
@@ -85,6 +89,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;
@@ -107,8 +112,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;
 
@@ -467,6 +472,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) {
@@ -504,6 +510,8 @@ void atp_send_replies(atp, rcbp)
        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))) {
@@ -586,9 +594,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);
@@ -601,7 +610,7 @@ nothing_to_send:
 } /* atp_send_replies */
 
 
-static void
+static int
 atp_pack_bdsp(trp, bdsp)
      register struct atp_trans *trp;
      register struct atpBDS *bdsp;
@@ -609,12 +618,13 @@ atp_pack_bdsp(trp, bdsp)
        register gbuf_t *m = NULL;
        register int i, datsize = 0;
        struct atpBDS *bdsbase = bdsp;
+       int error = 0;
 
        dPrintf(D_M_ATP, D_L_INFO, ("atp_pack_bdsp: socket=%d\n",
                trp->tr_queue->atp_socket_no));
 
        for (i = 0; i < ATP_TRESP_MAX; i++, bdsp++) {
-               short bufsize = UAS_VALUE(bdsp->bdsBuffSz);
+               unsigned short bufsize = UAS_VALUE(bdsp->bdsBuffSz);
                long bufaddr = UAL_VALUE(bdsp->bdsBuffAddr);
 
                if ((m = trp->tr_rcv[i]) == NULL)
@@ -636,15 +646,17 @@ atp_pack_bdsp(trp, bdsp)
                        register char *buf = (char *)bufaddr;
 
                        while (m) {
-                               short len = (short)(gbuf_len(m));
+                               unsigned short len = (unsigned short)(gbuf_len(m));
                                if (len) {
                                        if (len > bufsize)
                                                len = bufsize;
-                                       copyout((caddr_t)gbuf_rptr(m), 
-                                               (caddr_t)&buf[tmp],
-                                               len);
+                                       if ((error = copyout((caddr_t)gbuf_rptr(m), 
+                                               CAST_USER_ADDR_T(&buf[tmp]),
+                                               len)) != 0) {
+                                               return error;
+                                       }
                                        bufsize -= len;
-                                       tmp =+ len;
+                                       tmp += len;
                                }
                                m = gbuf_cont(m);
                        }
@@ -661,6 +673,8 @@ atp_pack_bdsp(trp, bdsp)
 
        dPrintf(D_M_ATP, D_L_INFO, ("             : size=%d\n",
                datsize));
+       
+       return 0;
 } /* atp_pack_bdsp */
 
 
@@ -690,6 +704,7 @@ atp_unpack_bdsp(atp, m, rcbp, cnt, wait)
        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
@@ -824,9 +839,10 @@ atp_unpack_bdsp(atp, m, rcbp, cnt, wait)
         */
 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);
                }
@@ -1121,12 +1137,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
@@ -1152,7 +1168,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
@@ -1260,20 +1276,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)
@@ -1374,7 +1390,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);
@@ -1444,24 +1460,38 @@ _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;
+       }
 
+       if (len < atpBDSsize + sizeof(struct atp_set_default) + TOTAL_ATP_HDR_SIZE ||
+               len > atpBDSsize + sizeof(struct atp_set_default) + TOTAL_ATP_HDR_SIZE + 
+               ATP_DATA_SIZE) {
+               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;
                }
                
@@ -1469,21 +1499,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);
@@ -1505,11 +1542,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;
                }
@@ -1572,8 +1615,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
@@ -1582,10 +1627,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;
                }
@@ -1599,6 +1645,7 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
                 * transaction timed out, return error
                 */
                atp_free(trp);
+               file_drop(fd);
                *err = ETIMEDOUT;
                return -1;
        }
@@ -1606,14 +1653,23 @@ _ATPsndreq(fd, buf, len, nowait, err, proc)
        /*
         * copy out the recv data
         */
-       atp_pack_bdsp(trp, bds);
+       if ((*err = atp_pack_bdsp(trp, (struct atpBDS *)bds)) != 0) {
+               atp_free(trp);
+               file_drop(fd);
+               return -1;
+       }
 
        /*
         * copyout the result info
         */
-       copyout((caddr_t)bds, (caddr_t)buf, atpBDSsize);
+       if ((*err = copyout((caddr_t)bds, CAST_USER_ADDR_T(buf), atpBDSsize)) != 0) {
+               atp_free(trp);
+               file_drop(fd);
+               return -1;
+       }
 
        atp_free(trp);
+       file_drop(fd);
 
        return (int)tid;
 } /* _ATPsndreq */
@@ -1648,7 +1704,7 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
        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)
@@ -1656,6 +1712,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;
        }
@@ -1663,12 +1720,19 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
        /*
         * allocate buffer and copy in the response info
         */
+       if (resplen < 0 || resplen > TOTAL_ATP_HDR_SIZE + sizeof(struct atpBDS)*ATP_TRESP_MAX) {
+               file_drop(fd);
+               *err = EINVAL;
+               return -1;
+       }
        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);
@@ -1685,21 +1749,30 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
        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++) {
+               if (UAS_VALUE(bdsp[count].bdsBuffSz) > ATP_DATA_SIZE) {
+                       gbuf_freem(m);
+                       *err = EINVAL;
+                       file_drop(fd);
+                       return -1;
+               }
                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;
        }
@@ -1713,6 +1786,7 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
                                /* 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;
                                }
@@ -1720,14 +1794,16 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
                                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((caddr_t)bufaddr, dataptr, len)) != 0) {
+                       if ((*err = copyin(CAST_USER_ADDR_T(bufaddr), dataptr, len)) != 0) {
                                gbuf_freem(m);
+                               file_drop(fd);
                                return -1;
                        }
                        dataptr += len;
@@ -1738,6 +1814,7 @@ _ATPsndrsp(fd, respbuff, resplen, datalen, err, proc)
        gbuf_cont(m)->m_pkthdr.len = size;                                              /* set packet hdr len */
 
        atp_send_rsp(gref, m, TRUE);
+       file_drop(fd);
        return 0;
 }
 
@@ -1755,13 +1832,20 @@ _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;
+       }
+
+       if (buflen < DDP_X_HDR_SIZE + ATP_HDR_SIZE) {
+               file_drop(fd);
                *err = EINVAL;
                return -1;
        }
@@ -1792,17 +1876,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;
 }
 
@@ -1819,13 +1905,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;
        }
@@ -1839,13 +1926,24 @@ _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) {
+                               atp_free(trp);
+                               file_drop(fd);
+                               return -1;
+                       }
+                       if ((*err = atp_pack_bdsp(trp, (struct atpBDS *)bds)) != 0) {
+                               atp_free(trp);
+                               file_drop(fd);
                                return -1;
-                       atp_pack_bdsp(trp, bds);
+                       }
                        tid = (int)trp->tr_tid;
                        atp_free(trp);
-                       copyout((caddr_t)bds, (caddr_t)bdsp, sizeof(bds));
+                       if ((*err = copyout((caddr_t)bds, CAST_USER_ADDR_T(bdsp), sizeof(bds))) != 0) {
+                               file_drop(fd);
+                               return -1;
+                       }
+                       file_drop(fd);
                        return tid;
 
                case TRANS_FAILED:
@@ -1854,6 +1952,7 @@ _ATPgetrsp(fd, bdsp, err, proc)
                         */
                ATENABLE(s, atp->atp_lock);
                        atp_free(trp);
+                       file_drop(fd);
                        *err = ETIMEDOUT;
                        return -1;
 
@@ -1863,6 +1962,7 @@ _ATPgetrsp(fd, bdsp, err, proc)
        }
        ATENABLE(s, atp->atp_lock);
 
+       file_drop(fd);
        *err = EINVAL;
        return -1;
 }