diff options
Diffstat (limited to 'sys/netncp/ncp_rq.c')
-rw-r--r-- | sys/netncp/ncp_rq.c | 591 |
1 files changed, 591 insertions, 0 deletions
diff --git a/sys/netncp/ncp_rq.c b/sys/netncp/ncp_rq.c new file mode 100644 index 0000000..8cef7d2 --- /dev/null +++ b/sys/netncp/ncp_rq.c @@ -0,0 +1,591 @@ +/* + * Copyright (c) 1999, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Routines to prepare request and fetch reply + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/mbuf.h> +#include <sys/uio.h> + +#include <netncp/ncp.h> +#include <netncp/ncp_conn.h> +#include <netncp/ncp_rq.h> +#include <netncp/ncp_subr.h> +#include <netncp/ncp_ncp.h> +#include <netncp/ncp_nls.h> + +static struct mbuf* m_getm(struct mbuf *top, int len); + +int +ncp_rq_head(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,struct proc *p, + struct ucred *cred) +{ + struct mbuf *m; + struct ncp_rqhdr *rq; + struct ncp_bursthdr *brq; + caddr_t pstart; + + bzero(rqp, sizeof(*rqp)); + rqp->p = p; + rqp->cred = cred; + m = m_gethdr(M_WAIT, MT_DATA); + if (m == NULL) + return ENOBUFS; /* if M_WAIT ? */ + m->m_pkthdr.rcvif = NULL; + rqp->rq = rqp->mrq = m; + rqp->rp = NULL; + switch(ptype) { + case NCP_PACKET_BURST: + MH_ALIGN(m, sizeof(*brq) + 24); + m->m_len = sizeof(*brq); + brq = mtod(m, struct ncp_bursthdr *); + brq->bh_type = ptype; + brq->bh_streamtype = 0x2; + pstart = (caddr_t)brq; + break; + default: + MH_ALIGN(m, sizeof(*rq) + 2); /* possible len field in some functions */ + m->m_len = sizeof(*rq); + rq = mtod(m, struct ncp_rqhdr *); + rq->type = ptype; + rq->seq = 0; /* filled later */ + rq->fn = fn; + pstart = (caddr_t)rq; + break; + } + rqp->bpos = pstart + m->m_len; + return 0; +} + +int +ncp_rq_done(struct ncp_rq *rqp) { + m_freem(rqp->rq); + rqp->rq=NULL; + if (rqp->rp) m_freem(rqp->rp); + rqp->rp=NULL; + return (0); +} + +static struct mbuf* +m_getm(struct mbuf *top, int len) { + int rest = len, mlen; + struct mbuf *m=0,*mp; + + mp = top; + while (rest > 0) { +/* NCPSDEBUG("%d\n",rest);*/ + m = m_get(M_WAIT, MT_DATA); + if (rest > MINCLSIZE) { + MCLGET(m,M_WAIT); + mlen = ( (m->m_flags & M_EXT) == 0) ? MLEN : MCLBYTES; + } else { + mlen = MLEN; + } + m->m_len = 0/*min(mlen,rest)*/; + mp->m_next = m; + mp = m; + rest -= mlen; + } + return top; +} + +/* + * Routines to fill the request + */ +static caddr_t ncp_mchecksize(struct ncp_rq *rqp, int size); +#define NCP_RQADD(t) ((t*)(ncp_mchecksize(rqp,sizeof(t)))) + +caddr_t +ncp_mchecksize(struct ncp_rq *rqp, int size) { + caddr_t bpos1; + + if (size>MLEN) + panic("ncp_mchecksize\n"); + if (M_TRAILINGSPACE(rqp->mrq)<(size)) { + struct mbuf *m; + m = m_get(M_WAIT, MT_DATA); + m->m_len = 0; + rqp->bpos = mtod(m, caddr_t); + rqp->mrq->m_next = m; + rqp->mrq = m; + } + rqp->mrq->m_len += size; + bpos1 = rqp->bpos; + rqp->bpos += size; + return bpos1; +} + +void +ncp_rq_byte(struct ncp_rq *rqp,u_int8_t x) { + *NCP_RQADD(u_int8_t)=x; +} + +void +ncp_rq_word_hl(struct ncp_rq *rqp, u_int16_t x) { + setwbe(NCP_RQADD(u_int16_t), 0, x); +} + +void +ncp_rq_word_lh(struct ncp_rq *rqp, u_int16_t x) { + setwle(NCP_RQADD(u_int16_t), 0, x); +} + +void +ncp_rq_dword_lh(struct ncp_rq *rqp, u_int32_t x) { + setdle(NCP_RQADD(u_int32_t), 0, x); +} + +void +ncp_rq_pathstring(struct ncp_rq *rqp, int size, char *name, struct ncp_nlstables *nt) { + struct mbuf *m; + int cplen; + + ncp_rq_byte(rqp, size); + m = rqp->mrq; + cplen = min(size, M_TRAILINGSPACE(m)); + if (cplen) { + ncp_pathcopy(name, rqp->bpos, cplen, nt); + size -= cplen; + name += cplen; + m->m_len += cplen; + } + if (size) { + m_getm(m, size); + while (size > 0){ + m = m->m_next; + cplen = min(size, M_TRAILINGSPACE(m)); + ncp_pathcopy(name, mtod(m, caddr_t) + m->m_len, cplen, nt); + size -= cplen; + name += cplen; + m->m_len += cplen; + } + } + rqp->bpos = mtod(m,caddr_t) + m->m_len; + rqp->mrq = m; + return; +} + +int +ncp_rq_putanymem(struct ncp_rq *rqp, caddr_t source, int size, int type) { + struct mbuf *m; + int cplen, error; + + m = rqp->mrq; + cplen = min(size, M_TRAILINGSPACE(m)); + if (cplen) { + if (type==1) { + error = copyin(source, rqp->bpos, cplen); + if (error) return error; + } else + bcopy(source, rqp->bpos, cplen); + size -= cplen; + source += cplen; + m->m_len += cplen; + } + if (size) { + m_getm(m, size); + while (size > 0){ + m = m->m_next; + cplen = min(size, M_TRAILINGSPACE(m)); + if (type==1) { + error = copyin(source, mtod(m, caddr_t) + m->m_len, cplen); + if (error) return error; + } else + bcopy(source, mtod(m, caddr_t) + m->m_len, cplen); + size -= cplen; + source += cplen; + m->m_len += cplen; + } + } + rqp->bpos = mtod(m,caddr_t) + m->m_len; + rqp->mrq = m; + return 0; +} + +int +ncp_rq_mbuf(struct ncp_rq *rqp, struct mbuf *m, int size) { + + rqp->mrq->m_next = m; + m->m_next = NULL; + if (size != M_COPYALL) m->m_len = size; + rqp->bpos = mtod(m,caddr_t) + m->m_len; + rqp->mrq = m; + return 0; +} + +void +ncp_rq_pstring(struct ncp_rq *rqp, char *s) { + int len = strlen(s); + if (len > 255) { + nwfs_printf("string too long: %s\n", s); + len = 255; + } + ncp_rq_byte(rqp, len); + ncp_rq_mem(rqp, s, len); + return; +} + +void +ncp_rq_dbase_path(struct ncp_rq *rqp, u_int8_t vol_num, u_int32_t dir_base, + int namelen, u_char *path, struct ncp_nlstables *nt) +{ + int complen; + + ncp_rq_byte(rqp, vol_num); + ncp_rq_dword(rqp, dir_base); + ncp_rq_byte(rqp, 1); /* with dirbase */ + if (path != NULL && path[0]) { + if (namelen < 0) { + namelen = *path++; + ncp_rq_byte(rqp, namelen); + for(; namelen; namelen--) { + complen = *path++; + ncp_rq_byte(rqp, complen); + ncp_rq_mem(rqp, path, complen); + path += complen; + } + } else { + ncp_rq_byte(rqp, 1); /* 1 component */ + ncp_rq_pathstring(rqp, namelen, path, nt); + } + } else { + ncp_rq_byte(rqp, 0); + ncp_rq_byte(rqp, 0); + } +} +/* + * fetch reply routines + */ +#define ncp_mspaceleft (mtod(rqp->mrp,caddr_t)+rqp->mrp->m_len-rqp->bpos) + +u_int8_t +ncp_rp_byte(struct ncp_rq *rqp) { + if (rqp->mrp == NULL) return 0; + if (ncp_mspaceleft < 1) { + rqp->mrp = rqp->mrp->m_next; + if (rqp->mrp == NULL) return 0; + rqp->bpos = mtod(rqp->mrp, caddr_t); + } + rqp->bpos += 1; + return rqp->bpos[-1]; +} + +u_int16_t +ncp_rp_word_lh(struct ncp_rq *rqp) { + caddr_t prev = rqp->bpos; + u_int16_t t; + + if (rqp->mrp == NULL) return 0; + if (ncp_mspaceleft >= 2) { + rqp->bpos += 2; + return getwle(prev,0); + } + t = *((u_int8_t*)(rqp->bpos)); + rqp->mrp = rqp->mrp->m_next; + if (rqp->mrp == NULL) return 0; + ((u_int8_t *)&t)[1] = *((u_int8_t*)(rqp->bpos = mtod(rqp->mrp, caddr_t))); + rqp->bpos += 2; + return t; +} + +u_int16_t +ncp_rp_word_hl(struct ncp_rq *rqp) { + return (ntohs(ncp_rp_word_lh(rqp))); +} + +u_int32_t +ncp_rp_dword_hl(struct ncp_rq *rqp) { + int togo, rest; + caddr_t prev = rqp->bpos; + u_int32_t t; + + if (rqp->mrp == NULL) return 0; + rest = ncp_mspaceleft; + if (rest >= 4) { + rqp->bpos += 4; + return getdbe(prev,0); + } + togo = 0; + while (rest--) { + ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++)); + } + rqp->mrp = rqp->mrp->m_next; + if (rqp->mrp == NULL) return 0; + prev = mtod(rqp->mrp, caddr_t); + rqp->bpos = prev + 4 - togo; /* XXX possible low than togo bytes in next mbuf */ + while (togo < 4) { + ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++)); + } + return getdbe(&t,0); +} + +u_int32_t +ncp_rp_dword_lh(struct ncp_rq *rqp) { + int rest, togo; + caddr_t prev = rqp->bpos; + u_int32_t t; + + if (rqp->mrp == NULL) return 0; + rest = ncp_mspaceleft; + if (rest >= 4) { + rqp->bpos += 4; + return getdle(prev,0); + } + togo = 0; + while (rest--) { + ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++)); + } + rqp->mrp = rqp->mrp->m_next; + if (rqp->mrp == NULL) return 0; + prev = mtod(rqp->mrp, caddr_t); + rqp->bpos = prev + 4 - togo; /* XXX possible low than togo bytes in next mbuf */ + while (togo < 4) { + ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++)); + } + return getdle(&t,0); +} +void +ncp_rp_mem(struct ncp_rq *rqp,caddr_t target, int size) { + register struct mbuf *m=rqp->mrp; + register unsigned count; + + while (size > 0) { + if (m==0) { /* should be panic */ + printf("ncp_rp_mem: incomplete copy\n"); + return; + } + count = mtod(m,caddr_t)+m->m_len-rqp->bpos; + if (count == 0) { + m=m->m_next; + rqp->bpos=mtod(m,caddr_t); + continue; + } + count = min(count,size); + bcopy(rqp->bpos, target, count); + size -= count; + target += count; + rqp->bpos += count; + } + rqp->mrp=m; + return; +} + +int +ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size) { + register struct mbuf *m=rqp->mrp; + register unsigned count; + int error; + + while (size>0) { + if (m==0) { /* should be panic */ + printf("ncp_rp_mem: incomplete copy\n"); + return EFAULT; + } + count = mtod(m,caddr_t)+m->m_len-rqp->bpos; + if (count == 0) { + m=m->m_next; + rqp->bpos=mtod(m,caddr_t); + continue; + } + count = min(count,size); + error=copyout(rqp->bpos, target, count); + if (error) return error; + size -= count; + target += count; + rqp->bpos += count; + } + rqp->mrp=m; + return 0; +} + +struct mbuf* +ncp_rp_mbuf(struct ncp_rq *rqp, int size) { + register struct mbuf *m=rqp->mrp, *rm; + register unsigned count; + + rm = m_copym(m, rqp->bpos - mtod(m,caddr_t), size, M_WAIT); + while (size > 0) { + if (m == 0) { + printf("ncp_rp_mbuf: can't advance\n"); + return rm; + } + count = mtod(m,caddr_t)+ m->m_len - rqp->bpos; + if (count == 0) { + m = m->m_next; + rqp->bpos = mtod(m, caddr_t); + continue; + } + count = min(count, size); + size -= count; + rqp->bpos += count; + } + rqp->mrp=m; + return rm; +} + +int +nwfs_mbuftouio(mrep, uiop, siz, dpos) + struct mbuf **mrep; + register struct uio *uiop; + int siz; + caddr_t *dpos; +{ + register char *mbufcp, *uiocp; + register int xfer, left, len; + register struct mbuf *mp; + long uiosiz; + int error = 0; + + mp = *mrep; + if (!mp) return 0; + mbufcp = *dpos; + len = mtod(mp, caddr_t)+mp->m_len-mbufcp; + while (siz > 0) { + if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) + return (EFBIG); + left = uiop->uio_iov->iov_len; + uiocp = uiop->uio_iov->iov_base; + if (left > siz) + left = siz; + uiosiz = left; + while (left > 0) { + while (len == 0) { + mp = mp->m_next; + if (mp == NULL) + return (EBADRPC); + mbufcp = mtod(mp, caddr_t); + len = mp->m_len; + } + xfer = (left > len) ? len : left; +#ifdef notdef + /* Not Yet.. */ + if (uiop->uio_iov->iov_op != NULL) + (*(uiop->uio_iov->iov_op)) + (mbufcp, uiocp, xfer); + else +#endif + if (uiop->uio_segflg == UIO_SYSSPACE) + bcopy(mbufcp, uiocp, xfer); + else + copyout(mbufcp, uiocp, xfer); + left -= xfer; + len -= xfer; + mbufcp += xfer; + uiocp += xfer; + uiop->uio_offset += xfer; + uiop->uio_resid -= xfer; + } + if (uiop->uio_iov->iov_len <= siz) { + uiop->uio_iovcnt--; + uiop->uio_iov++; + } else { + uiop->uio_iov->iov_base += uiosiz; + uiop->uio_iov->iov_len -= uiosiz; + } + siz -= uiosiz; + } + *dpos = mbufcp; + *mrep = mp; + return (error); +} +/* + * copies a uio scatter/gather list to an mbuf chain. + * NOTE: can ony handle iovcnt == 1 + */ +int +nwfs_uiotombuf(uiop, mq, siz, bpos) + register struct uio *uiop; + struct mbuf **mq; + int siz; + caddr_t *bpos; +{ + register char *uiocp; + register struct mbuf *mp, *mp2; + register int xfer, left, mlen; + int uiosiz, clflg; + +#ifdef DIAGNOSTIC + if (uiop->uio_iovcnt != 1) + panic("nfsm_uiotombuf: iovcnt != 1"); +#endif + + if (siz > MLEN) /* or should it >= MCLBYTES ?? */ + clflg = 1; + else + clflg = 0; + mp = mp2 = *mq; + while (siz > 0) { + left = uiop->uio_iov->iov_len; + uiocp = uiop->uio_iov->iov_base; + if (left > siz) + left = siz; + uiosiz = left; + while (left > 0) { + mlen = M_TRAILINGSPACE(mp); + if (mlen == 0) { + MGET(mp, M_WAIT, MT_DATA); + if (clflg) + MCLGET(mp, M_WAIT); + mp->m_len = 0; + mp2->m_next = mp; + mp2 = mp; + mlen = M_TRAILINGSPACE(mp); + } + xfer = (left > mlen) ? mlen : left; +#ifdef notdef + /* Not Yet.. */ + if (uiop->uio_iov->iov_op != NULL) + (*(uiop->uio_iov->iov_op)) + (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); + else +#endif + if (uiop->uio_segflg == UIO_SYSSPACE) + bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); + else + copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); + mp->m_len += xfer; + left -= xfer; + uiocp += xfer; + uiop->uio_offset += xfer; + uiop->uio_resid -= xfer; + } + uiop->uio_iov->iov_base += uiosiz; + uiop->uio_iov->iov_len -= uiosiz; + siz -= uiosiz; + } + *bpos = mtod(mp, caddr_t)+mp->m_len; + *mq = mp; + return (0); +} |