X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/14353aa8f494621e510528b7be0e0f4ff82fdefb..91447636331957f3d9b5ca5b508f07c526b0074d:/bsd/netat/atp_write.c diff --git a/bsd/netat/atp_write.c b/bsd/netat/atp_write.c index 4fea05d13..865962ef6 100644 --- a/bsd/netat/atp_write.c +++ b/bsd/netat/atp_write.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -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; }