summaryrefslogtreecommitdiffstats
path: root/sys/netncp/ncp_rq.c
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>1999-10-02 04:06:24 +0000
committerbp <bp@FreeBSD.org>1999-10-02 04:06:24 +0000
commit99edac4b3b7b369e65394b2bd57332aaad8d6812 (patch)
tree648f799b08d76bc3345446a922bb7985b440fae9 /sys/netncp/ncp_rq.c
parent4f9461c0bd8dd6d2fb8a4f0df36c1666e4e25c98 (diff)
downloadFreeBSD-src-99edac4b3b7b369e65394b2bd57332aaad8d6812.zip
FreeBSD-src-99edac4b3b7b369e65394b2bd57332aaad8d6812.tar.gz
Import kernel part of ncplib: netncp and nwfs
Reviewed by: msmith, peter Obtained from: ncplib
Diffstat (limited to 'sys/netncp/ncp_rq.c')
-rw-r--r--sys/netncp/ncp_rq.c591
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);
+}
OpenPOWER on IntegriCloud