diff options
author | Boris Popov <bp@FreeBSD.org> | 2001-03-10 05:24:45 +0000 |
---|---|---|
committer | Boris Popov <bp@FreeBSD.org> | 2001-03-10 05:24:45 +0000 |
commit | 29ad26f932b432ca14c4ae27243aced04861d089 (patch) | |
tree | c6d3d45be821a1f3706fc1c7e88cdf7b2deaee0b /sys/netncp/ncp_ncp.c | |
parent | df54111fe4f2e0755b863d11a4da201e9f1ff506 (diff) | |
download | src-29ad26f932b432ca14c4ae27243aced04861d089.tar.gz src-29ad26f932b432ca14c4ae27243aced04861d089.zip |
Major update of NCP requester:
Use mchain API to work with mbuf chains.
Do not depend on INET and IPX options.
Allocate ncp_rq structure dynamically to prevent possible stack overflows.
Let ncp_request() dispose control structure if request failed.
Move all NCP wrappers to ncp_ncp.c file and all NCP request processing
functions to ncp_rq.c file.
Improve reconnection logic.
Misc style fixes.
Notes
Notes:
svn path=/head/; revision=74060
Diffstat (limited to 'sys/netncp/ncp_ncp.c')
-rw-r--r-- | sys/netncp/ncp_ncp.c | 623 |
1 files changed, 202 insertions, 421 deletions
diff --git a/sys/netncp/ncp_ncp.c b/sys/netncp/ncp_ncp.c index 69a77760a752..43a388be81fb 100644 --- a/sys/netncp/ncp_ncp.c +++ b/sys/netncp/ncp_ncp.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, Boris Popov + * Copyright (c) 1999, 2000, 2001 Boris Popov * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,21 +33,17 @@ * * Core of NCP protocol */ -#include "opt_inet.h" -#include "opt_ipx.h" #include <sys/param.h> #include <sys/errno.h> #include <sys/systm.h> #include <sys/proc.h> -#include <sys/poll.h> #include <sys/signalvar.h> #include <sys/mbuf.h> +#include <sys/uio.h> -#ifdef IPX #include <netipx/ipx.h> #include <netipx/ipx_var.h> -#endif #include <netncp/ncp.h> #include <netncp/ncp_conn.h> @@ -57,12 +53,6 @@ #include <netncp/ncp_rq.h> #include <netncp/nwerror.h> -static int ncp_do_request(struct ncp_conn *,struct ncp_rq *rqp); -static int ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target); -static int ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options); -static void ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size); - - #ifdef NCP_DATA_DEBUG static void m_dumpm(struct mbuf *m) { @@ -103,374 +93,132 @@ ncp_chkintr(struct ncp_conn *conn, struct proc *p) * should be called with LOCKED connection, also they use procp & ucred */ int -ncp_ncp_connect(struct ncp_conn *conn) { - int error; +ncp_ncp_connect(struct ncp_conn *conn) +{ + struct ncp_rq *rqp; struct ncp_rphdr *rp; - DECLARE_RQ; + int error; - conn->flags &= ~(NCPFL_INVALID | NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED); + error = ncp_rq_alloc_any(NCP_ALLOC_SLOT, 0, conn, conn->procp, conn->ucred, &rqp); + if (error) + return error; + + conn->flags &= ~(NCPFL_INVALID | NCPFL_SIGNACTIVE | NCPFL_SIGNWANTED + | NCPFL_ATTACHED); conn->seq = 0; - checkbad(ncp_rq_head(rqp,NCP_ALLOC_SLOT,0,conn->procp,conn->ucred)); - error=ncp_do_request(conn,rqp); + error = ncp_request_int(rqp); if (!error) { - rp = mtod(rqp->rp, struct ncp_rphdr*); + rp = mtod(rqp->rp.md_top, struct ncp_rphdr*); conn->connid = rp->conn_low + (rp->conn_high << 8); } ncp_rq_done(rqp); - if (error) return error; - conn->flags |= NCPFL_ATTACHED; - - error = ncp_renegotiate_connparam(conn, NCP_DEFAULT_BUFSIZE, 0); - if (error == NWE_SIGNATURE_LEVEL_CONFLICT) { - printf("Unable to negotiate requested security level\n"); - error = EOPNOTSUPP; - } - if (error) { - ncp_ncp_disconnect(conn); + if (error) return error; - } -#ifdef NCPBURST - ncp_burst_connect(conn); -#endif -bad: - return error; + conn->flags |= NCPFL_ATTACHED | NCPFL_WASATTACHED; + return 0; } int -ncp_ncp_disconnect(struct ncp_conn *conn) { +ncp_ncp_disconnect(struct ncp_conn *conn) +{ + struct ncp_rq *rqp; int error; - struct ncp_rqhdr *ncprq; - DECLARE_RQ; NCPSDEBUG("for connid=%d\n",conn->nc_id); #ifdef NCPBURST ncp_burst_disconnect(conn); #endif - error=ncp_rq_head(rqp,NCP_FREE_SLOT,0,conn->procp,conn->ucred); - ncprq = mtod(rqp->rq,struct ncp_rqhdr*); - error=ncp_do_request(conn,rqp); - ncp_rq_done(rqp); - ncp_conn_invalidate(conn); - ncp_sock_disconnect(conn); - return 0; -} -/* - * Make a signature for the current packet and add it at the end of the - * packet. - */ -static void -ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size) { - u_char data[64]; - - bzero(data, sizeof(data)); - bcopy(conn->sign_root, data, 8); - setdle(data, 8, *size); - m_copydata(rqp->rq, sizeof(struct ncp_rqhdr)-1, - min((*size) - sizeof(struct ncp_rqhdr)+1, 52),data+12); - ncp_sign(conn->sign_state, data, conn->sign_state); - ncp_rq_mem(rqp, (void*)conn->sign_state, 8); - (*size) += 8; -} - -/* - * Low level send rpc, here we do not attempt to restore any connection, - * Connection expected to be locked - */ -static int -ncp_do_request(struct ncp_conn *conn, struct ncp_rq *rqp) { - int error=EIO,len, dosend, plen = 0, gotpacket, s; - struct socket *so; - struct proc *p = conn->procp; - struct ncp_rqhdr *rq; - struct ncp_rphdr *rp=NULL; - struct timeval tv; - struct mbuf *m, *mreply = NULL; - - conn->nc_rq = rqp; - rqp->conn = conn; - if (p == NULL) - p = curproc; /* XXX maybe procpage ? */ - if (!ncp_conn_valid(conn)) { - printf("%s: conn not valid\n",__FUNCTION__); - return (error); - } - so = conn->ncp_so; - if (!so) { - printf("%s: ncp_so is NULL !\n",__FUNCTION__); - ncp_conn_invalidate(conn); /* wow ! how we do that ? */ - return EBADF; - } - /* - * Flush out replies on previous reqs - */ - s = splnet(); - while (1/*so->so_rcv.sb_cc*/) { - if (ncp_poll(so,POLLIN) == 0) break; - if (ncp_sock_recv(so,&m,&len) != 0) break; - m_freem(m); - } - rq = mtod(rqp->rq,struct ncp_rqhdr *); - rq->seq = conn->seq; - m = rqp->rq; - len = 0; - while (m) { - len += m->m_len; - m = m->m_next; - } - rqp->rq->m_pkthdr.len = len; - switch(rq->fn) { - case 0x15: case 0x16: case 0x17: case 0x23: - m = rqp->rq; - *((u_int16_t*)(mtod(m,u_int8_t*)+sizeof(*rq))) = htons(len-2-sizeof(*rq)); - break; - } - if (conn->flags & NCPFL_SIGNACTIVE) { - ncp_sign_packet(conn, rqp, &len); - rqp->rq->m_pkthdr.len = len; - } - rq->conn_low = conn->connid & 0xff; - /* rq->task = p->p_pgrp->pg_id & 0xff; */ /*p->p_pid*/ - /* XXX: this is temporary fix till I find a better solution */ - rq->task = rq->conn_low; - rq->conn_high = conn->connid >> 8; - rqp->rexmit = conn->li.retry_count; - for(dosend = 1;;) { - if (rqp->rexmit-- == 0) { - error = ETIMEDOUT; - break; + if (conn->flags & NCPFL_ATTACHED) { + error = ncp_rq_alloc_any(NCP_FREE_SLOT, 0, conn, conn->procp, conn->ucred, &rqp); + if (!error) { + ncp_request_int(rqp); + ncp_rq_done(rqp); } - error = 0; - if (dosend) { - NCPSDEBUG("send:%04x f=%02x c=%d l=%d s=%d t=%d\n",rq->type, rq->fn, (rq->conn_high << 8) + rq->conn_low, - rqp->rq->m_pkthdr.len, rq->seq, rq->task - ); - error = ncp_sock_send(so, rqp->rq, rqp); - if (error) break; - } - tv.tv_sec = conn->li.timeout; - tv.tv_usec = 0; - error = ncp_sock_rselect(so, p, &tv, POLLIN); - if (error == EWOULDBLOCK ) /* timeout expired */ - continue; - error = ncp_chkintr(conn, p); - if (error == EINTR) /* we dont restart */ - break; - if (error) break; - /* - * At this point it is possible to get more than one - * reply from server. In general, last reply should be for - * current request, but not always. So, we loop through - * all replies to find the right answer and flush others. - */ - gotpacket = 0; /* nothing good found */ - dosend = 1; /* resend rq if error */ - for (;;) { - error = 0; - if (ncp_poll(so,POLLIN) == 0) break; -/* if (so->so_rcv.sb_cc == 0) { - break; - }*/ - error = ncp_sock_recv(so,&m,&len); - if (error) break; /* must be more checks !!! */ - if (m->m_len < sizeof(*rp)) { - m = m_pullup(m, sizeof(*rp)); - if (m == NULL) { - printf("%s: reply too short\n",__FUNCTION__); - continue; - } - } - rp = mtod(m, struct ncp_rphdr*); - if (len == sizeof(*rp) && rp->type == NCP_POSITIVE_ACK) { - NCPSDEBUG("got positive acknowledge\n"); - m_freem(m); - rqp->rexmit = conn->li.retry_count; - dosend = 0; /* server just busy and will reply ASAP */ - continue; - } - NCPSDEBUG("recv:%04x c=%d l=%d s=%d t=%d cc=%02x cs=%02x\n",rp->type, - (rp->conn_high << 8) + rp->conn_low, len, rp->seq, rp->task, - rp->completion_code, rp->connection_state); - NCPDDEBUG(m); - if ( (rp->type == NCP_REPLY) && - ((rq->type == NCP_ALLOC_SLOT) || - ((rp->conn_low == rq->conn_low) && - (rp->conn_high == rq->conn_high) - ))) { - if (rq->seq > rp->seq || (rq->seq == 0 && rp->seq == 0xff)) { - dosend = 1; - } - if (rp->seq == rq->seq) { - if (gotpacket) { - m_freem(m); - } else { - gotpacket = 1; - mreply = m; - plen = len; - } - continue; /* look up other for other packets */ - } - } - m_freem(m); - NCPSDEBUG("reply mismatch\n"); - } /* for receive */ - if (error) break; - if (gotpacket) break; - /* try to resend, or just wait */ - } - splx(s); - conn->seq++; - if (error) { - NCPSDEBUG("error=%d\n",error); - if (error != EINTR) /* if not just interrupt */ - ncp_conn_invalidate(conn); /* only reconnect to restore */ - return(error); - } - if (conn->flags & NCPFL_SIGNACTIVE) { - /* XXX: check reply signature */ - m_adj(mreply, -8); - plen -= 8; } - len = plen; - m = mreply; - rp = mtod(m, struct ncp_rphdr*); - len -= sizeof(*rp); - rqp->rpsize = len; - rqp->cc = error = rp->completion_code; - if (error) error |= 0x8900; /* server error */ - rqp->cs = rp->connection_state; - if (rqp->cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) { - NCPSDEBUG("server drop us\n"); - ncp_conn_invalidate(conn); - error = ECONNRESET; - } - rqp->rp = m; - rqp->mrp = m; - rqp->bpos = mtod(m, caddr_t) + sizeof(*rp); - return error; + conn->flags |= NCPFL_INVALID; + ncp_sock_disconnect(conn); + return 0; } /* - * Here we will try to restore any loggedin & dropped connection, - * connection should be locked on entry + * All negotiation functions expect a locked connection */ -int ncp_restore_login(struct ncp_conn *conn); -int -ncp_restore_login(struct ncp_conn *conn) { - int error, oldflags; - - if (conn->flags & NCPFL_RESTORING) { - printf("Hey, ncp_restore_login called twise !!!\n"); - return 0; - } - oldflags = conn->flags; - printf("Restoring connection, flags = %d\n",oldflags); - if ((oldflags & NCPFL_LOGGED) == 0) { - return ECONNRESET; /* no need to restore empty conn */ - } - conn->flags &= ~(NCPFL_LOGGED | NCPFL_ATTACHED); - conn->flags |= NCPFL_RESTORING; - do { /* not a loop */ - error = ncp_reconnect(conn); - if (error) break; - if (conn->li.user) - error = ncp_login_object(conn, conn->li.user, conn->li.objtype, conn->li.password,conn->procp,conn->ucred); - if (error) break; - conn->flags |= NCPFL_LOGGED; - } while(0); - if (error) { - conn->flags = oldflags | NCPFL_INVALID; - } - conn->flags &= ~NCPFL_RESTORING; - return error; -} int -ncp_request(struct ncp_conn *conn, struct ncp_rq *rqp) { - int error, rcnt; -/* struct ncp_rqhdr *rq = mtod(rqp->rq,struct ncp_rqhdr*);*/ - - error = ncp_conn_lock(conn,rqp->p,rqp->cred,NCPM_EXECUTE); - if (error) return error; - rcnt = NCP_RESTORE_COUNT; - for(;;) { - if (!ncp_conn_valid(conn)) { - if (rcnt==0) { - error = ECONNRESET; - break; - } - rcnt--; - error = ncp_restore_login(conn); - if (error) - continue; - } - error=ncp_do_request(conn, rqp); - if (ncp_conn_valid(conn)) /* not just error ! */ - break; - } - ncp_conn_unlock(conn,rqp->p); - return error; -} - -/* - * All negotiation functions expect a locked connection - */ -static int -ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target) { +ncp_negotiate_buffersize(struct ncp_conn *conn, int size, int *target) +{ + struct ncp_rq *rqp; + u_int16_t bsize; int error; - DECLARE_RQ; - NCP_RQ_HEAD(0x21,conn->procp,conn->ucred); - ncp_rq_word_hl(rqp, size); - checkbad(ncp_request(conn,rqp)); - *target = min(ncp_rp_word_hl(rqp), size); - NCP_RQ_EXIT; + error = ncp_rq_alloc(0x21, conn, conn->procp, conn->ucred, &rqp); + if (error) + return error; + mb_put_uint16be(&rqp->rq, size); + error = ncp_request(rqp); + if (error) + return error; + md_get_uint16be(&rqp->rp, &bsize); + *target = min(bsize, size); + ncp_rq_done(rqp); return error; } static int ncp_negotiate_size_and_options(struct ncp_conn *conn, int size, int options, - int *ret_size, int *ret_options) { + int *ret_size, u_int8_t *ret_options) +{ + struct ncp_rq *rqp; + u_int16_t rs; int error; - int rs; - DECLARE_RQ; - NCP_RQ_HEAD(0x61,conn->procp,conn->ucred); - ncp_rq_word_hl(rqp, size); - ncp_rq_byte(rqp, options); - checkbad(ncp_request(conn, rqp)); - rs = ncp_rp_word_hl(rqp); + error = ncp_rq_alloc(0x61, conn, conn->procp, conn->ucred, &rqp); + if (error) + return error; + mb_put_uint16be(&rqp->rq, size); + mb_put_uint8(&rqp->rq, options); + rqp->nr_minrplen = 2 + 2 + 1; + error = ncp_request(rqp); + if (error) + return error; + md_get_uint16be(&rqp->rp, &rs); *ret_size = (rs == 0) ? size : min(rs, size); - ncp_rp_word_hl(rqp); /* skip echo socket */ - *ret_options = ncp_rp_byte(rqp); - NCP_RQ_EXIT; + md_get_uint16be(&rqp->rp, &rs); /* skip echo socket */ + md_get_uint8(&rqp->rp, ret_options); + ncp_rq_done(rqp); return error; } -static int -ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options) +int +ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, u_int8_t in_options) { - int neg_buffsize, error, options, sl; + u_int8_t options; + int neg_buffsize, error, sl, ckslevel, ilen; sl = conn->li.sig_level; if (sl >= 2) in_options |= NCP_SECURITY_LEVEL_SIGN_HEADERS; -#ifdef IPX - if (ipxcksum == 2) - in_options |= NCP_IPX_CHECKSUM; -#endif + if (conn->li.saddr.sa_family == AF_IPX) { + ilen = sizeof(ckslevel); + error = ncp_sysctlbyname("net.ipx.ipx.checksum", &ckslevel, &ilen, + NULL, 0, NULL); + if (error) + return error; + if (ckslevel == 2) + in_options |= NCP_IPX_CHECKSUM; + } error = ncp_negotiate_size_and_options(conn, buffsize, in_options, &neg_buffsize, &options); if (!error) { -#ifdef IPX - if ((options ^ in_options) & NCP_IPX_CHECKSUM) { - if (ipxcksum == 2) { + if (conn->li.saddr.sa_family == AF_IPX && + ((options ^ in_options) & NCP_IPX_CHECKSUM)) { + if (ckslevel == 2) { printf("Server refuses to support IPX checksums\n"); return NWE_REQUESTER_FAILURE; } in_options |= NCP_IPX_CHECKSUM; error = 1; } -#endif /* IPX */ if ((options ^ in_options) & 2) { if (sl == 0 || sl == 3) return NWE_SIGNATURE_LEVEL_CONFLICT; @@ -497,115 +245,148 @@ ncp_renegotiate_connparam(struct ncp_conn *conn, int buffsize, int in_options) conn->buffer_size = neg_buffsize; if (in_options & NCP_SECURITY_LEVEL_SIGN_HEADERS) conn->flags |= NCPFL_SIGNWANTED; -#ifdef IPX - ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM); -#endif + if (conn->li.saddr.sa_family == AF_IPX) + ncp_sock_checksum(conn, in_options & NCP_IPX_CHECKSUM); return 0; } -int -ncp_reconnect(struct ncp_conn *conn) { - int error; - - /* close any open sockets */ - ncp_sock_disconnect(conn); - switch( conn->li.saddr.sa_family ) { -#ifdef IPX - case AF_IPX: - error = ncp_sock_connect_ipx(conn); - break; -#endif -#ifdef INET - case AF_INET: - error = ncp_sock_connect_in(conn); - break; -#endif - default: - return EPROTONOSUPPORT; +void +ncp_check_rq(struct ncp_conn *conn){ + return; + if (conn->flags & NCPFL_INTR) return; + /* first, check for signals */ + if (ncp_chkintr(conn,conn->procp)) { + conn->flags |= NCPFL_INTR; } - if (!error) - error = ncp_ncp_connect(conn); - return error; + return; } -/* - * Create conn structure and try to do low level connect - * Server addr should be filled in. - */ int -ncp_connect(struct ncp_conn_args *li, struct proc *p, struct ucred *cred, - struct ncp_conn **aconn) +ncp_get_bindery_object_id(struct ncp_conn *conn, + u_int16_t object_type, char *object_name, + struct ncp_bindery_object *target, + struct proc *p,struct ucred *cred) { - struct ncp_conn *conn; - struct ucred *owner; - int error, isroot; + struct ncp_rq *rqp; + int error; - if (li->saddr.sa_family != AF_INET && li->saddr.sa_family != AF_IPX) - return EPROTONOSUPPORT; - isroot = ncp_suser(cred) == 0; - /* - * Only root can change ownership - */ - if (li->owner != NCP_DEFAULT_OWNER && !isroot) - return EPERM; - if (li->group != NCP_DEFAULT_GROUP && - !groupmember(li->group, cred) && !isroot) - return EPERM; - if (li->owner != NCP_DEFAULT_OWNER) { - owner = crget(); - owner->cr_uid = li->owner; - } else { - owner = cred; - crhold(owner); - } - error = ncp_conn_alloc(p, owner, &conn); + error = ncp_rq_alloc_subfn(23, 53, conn, conn->procp, conn->ucred, &rqp); + mb_put_uint16be(&rqp->rq, object_type); + ncp_rq_pstring(rqp, object_name); + rqp->nr_minrplen = 54; + error = ncp_request(rqp); if (error) - return (error); - if (error) { - ncp_conn_free(conn); return error; - } - conn->li = *li; - conn->nc_group = (li->group != NCP_DEFAULT_GROUP) ? - li->group : cred->cr_groups[0]; - - if (li->retry_count == 0) - conn->li.retry_count = NCP_RETRY_COUNT; - if (li->timeout == 0) - conn->li.timeout = NCP_RETRY_TIMEOUT; - error = ncp_reconnect(conn); - if (error) { - ncp_disconnect(conn); - } else { - *aconn=conn; - } - return error; + md_get_uint32be(&rqp->rp, &target->object_id); + md_get_uint16be(&rqp->rp, &target->object_type); + md_get_mem(&rqp->rp, (caddr_t)target->object_name, 48, MB_MSYSTEM); + ncp_rq_done(rqp); + return 0; } -/* - * Break connection and deallocate memory - */ + int -ncp_disconnect(struct ncp_conn *conn) { +ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) +{ + struct ncp_rq *rqp; + struct mbchain *mbp; + u_int16_t retlen = 0 ; + int error = 0, len = 0, tsiz, burstio; + + tsiz = uiop->uio_resid; +#ifdef NCPBURST + burstio = (ncp_burst_enabled && tsiz > conn->buffer_size); +#else + burstio = 0; +#endif - if (ncp_conn_access(conn,conn->ucred,NCPM_WRITE)) - return EACCES; - if (conn->ref_cnt != 0) return EBUSY; - if (conn->flags & NCPFL_PERMANENT) return EBUSY; - if (ncp_conn_valid(conn)) { - ncp_ncp_disconnect(conn); + while (tsiz > 0) { + if (!burstio) { + len = min(4096 - (uiop->uio_offset % 4096), tsiz); + len = min(len, conn->buffer_size); + error = ncp_rq_alloc(72, conn, uiop->uio_procp, cred, &rqp); + if (error) + break; + mbp = &rqp->rq; + mb_put_uint8(mbp, 0); + mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM); + mb_put_uint32be(mbp, uiop->uio_offset); + mb_put_uint16be(mbp, len); + rqp->nr_minrplen = 2; + error = ncp_request(rqp); + if (error) + break; + md_get_uint16be(&rqp->rp, &retlen); + if (uiop->uio_offset & 1) + md_get_mem(&rqp->rp, NULL, 1, MB_MSYSTEM); + error = md_get_uio(&rqp->rp, uiop, retlen); + ncp_rq_done(rqp); + } else { +#ifdef NCPBURST + error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred); +#endif + } + if (error) + break; + tsiz -= retlen; + if (retlen < len) + break; } - ncp_sock_disconnect(conn); - ncp_conn_free(conn); - return 0; + return (error); } -void -ncp_check_rq(struct ncp_conn *conn){ - return; - if (conn->flags & NCPFL_INTR) return; - /* first, check for signals */ - if (ncp_chkintr(conn,conn->procp)) { - conn->flags |= NCPFL_INTR; +int +ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) +{ + struct ncp_rq *rqp; + struct mbchain *mbp; + int error = 0, len, tsiz, backup; + + if (uiop->uio_iovcnt != 1) { + printf("%s: can't handle iovcnt>1 !!!\n", __FUNCTION__); + return EIO; } - return; + tsiz = uiop->uio_resid; + while (tsiz > 0) { + len = min(4096 - (uiop->uio_offset % 4096), tsiz); + len = min(len, conn->buffer_size); + if (len == 0) { + printf("gotcha!\n"); + } + /* rq head */ + error = ncp_rq_alloc(73, conn, uiop->uio_procp, cred, &rqp); + if (error) + break; + mbp = &rqp->rq; + mb_put_uint8(mbp, 0); + mb_put_mem(mbp, (caddr_t)file, 6, MB_MSYSTEM); + mb_put_uint32be(mbp, uiop->uio_offset); + mb_put_uint16be(mbp, len); + error = mb_put_uio(mbp, uiop, len); + if (error) { + ncp_rq_done(rqp); + break; + } + error = ncp_request(rqp); + if (!error) + ncp_rq_done(rqp); + if (len == 0) + break; + if (error) { + backup = len; + uiop->uio_iov->iov_base -= backup; + uiop->uio_iov->iov_len += backup; + uiop->uio_offset -= backup; + uiop->uio_resid += backup; + break; + } + tsiz -= len; + } + if (error) + uiop->uio_resid = tsiz; + switch (error) { + case NWE_INSUFFICIENT_SPACE: + error = ENOSPC; + break; + } + return (error); } |