summaryrefslogtreecommitdiffstats
path: root/sys/netncp/ncp_rq.c
diff options
context:
space:
mode:
authorbp <bp@FreeBSD.org>2001-03-10 05:24:45 +0000
committerbp <bp@FreeBSD.org>2001-03-10 05:24:45 +0000
commitdde32853641c8191e1074cc8a3d9b3ae9facfa27 (patch)
tree3496a4f9320d911a7b3ce90b4c45fe032119f1d2 /sys/netncp/ncp_rq.c
parent04dc7092d8850e0118c795388fd40cbe91ee027e (diff)
downloadFreeBSD-src-dde32853641c8191e1074cc8a3d9b3ae9facfa27.zip
FreeBSD-src-dde32853641c8191e1074cc8a3d9b3ae9facfa27.tar.gz
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.
Diffstat (limited to 'sys/netncp/ncp_rq.c')
-rw-r--r--sys/netncp/ncp_rq.c786
1 files changed, 345 insertions, 441 deletions
diff --git a/sys/netncp/ncp_rq.c b/sys/netncp/ncp_rq.c
index dacdee0..fb53775 100644
--- a/sys/netncp/ncp_rq.c
+++ b/sys/netncp/ncp_rq.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
@@ -36,7 +36,10 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
#include <sys/mbuf.h>
+#include <sys/poll.h>
#include <sys/uio.h>
#include <netncp/ncp.h>
@@ -44,523 +47,424 @@
#include <netncp/ncp_rq.h>
#include <netncp/ncp_subr.h>
#include <netncp/ncp_ncp.h>
+#include <netncp/ncp_sock.h>
#include <netncp/ncp_nls.h>
+static MALLOC_DEFINE(M_NCPRQ, "NCPRQ", "NCP request");
+
+static int ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size);
+
+int
+ncp_rq_alloc_any(u_int32_t ptype, u_int8_t fn, struct ncp_conn *ncp,
+ struct proc *p, struct ucred *cred,
+ struct ncp_rq **rqpp)
+{
+ struct ncp_rq *rqp;
+ int error;
+
+ MALLOC(rqp, struct ncp_rq *, sizeof(*rqp), M_NCPRQ, M_WAITOK);
+ error = ncp_rq_init_any(rqp, ptype, fn, ncp, p, cred);
+ rqp->nr_flags |= NCPR_ALLOCED;
+ if (error) {
+ ncp_rq_done(rqp);
+ return error;
+ }
+ *rqpp = rqp;
+ return 0;
+}
+
+int
+ncp_rq_alloc(u_int8_t fn, struct ncp_conn *ncp,
+ struct proc *p, struct ucred *cred, struct ncp_rq **rqpp)
+{
+ return ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, p, cred, rqpp);
+}
+
int
-ncp_rq_head(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,struct proc *p,
- struct ucred *cred)
+ncp_rq_alloc_subfn(u_int8_t fn, u_int8_t subfn, struct ncp_conn *ncp,
+ struct proc *p, struct ucred *cred, struct ncp_rq **rqpp)
+{
+ struct ncp_rq *rqp;
+ int error;
+
+ error = ncp_rq_alloc_any(NCP_REQUEST, fn, ncp, p, cred, &rqp);
+ if (error)
+ return error;
+ mb_reserve(&rqp->rq, 2);
+ mb_put_uint8(&rqp->rq, subfn);
+ *rqpp = rqp;
+ return 0;
+}
+
+int
+ncp_rq_init_any(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,
+ struct ncp_conn *ncp,
+ struct proc *p, struct ucred *cred)
{
- struct mbuf *m;
struct ncp_rqhdr *rq;
struct ncp_bursthdr *brq;
- caddr_t pstart;
+ struct mbchain *mbp;
+ int error;
bzero(rqp, sizeof(*rqp));
- rqp->p = p;
- rqp->cred = cred;
- m = m_gethdr(M_TRYWAIT, MT_DATA);
- if (m == NULL)
- return ENOBUFS; /* if M_TRYWAIT ? */
- m->m_pkthdr.rcvif = NULL;
- rqp->rq = rqp->mrq = m;
- rqp->rp = NULL;
+ error = ncp_conn_access(ncp, cred, NCPM_EXECUTE);
+ if (error)
+ return error;
+ rqp->nr_p = p;
+ rqp->nr_cred = cred;
+ rqp->nr_conn = ncp;
+ mbp = &rqp->rq;
+ if (mb_init(mbp) != 0)
+ return ENOBUFS;
switch(ptype) {
case NCP_PACKET_BURST:
- MH_ALIGN(m, sizeof(*brq) + 24);
- m->m_len = sizeof(*brq);
- brq = mtod(m, struct ncp_bursthdr *);
+ brq = (struct ncp_bursthdr*)mb_reserve(mbp, sizeof(*brq));
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 = (struct ncp_rqhdr*)mb_reserve(mbp, sizeof(*rq));
rq->type = ptype;
rq->seq = 0; /* filled later */
rq->fn = fn;
- pstart = (caddr_t)rq;
break;
}
- rqp->bpos = pstart + m->m_len;
+ rqp->nr_minrplen = -1;
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);
+void
+ncp_rq_done(struct ncp_rq *rqp)
+{
+ mb_done(&rqp->rq);
+ md_done(&rqp->rp);
+ if (rqp->nr_flags & NCPR_ALLOCED)
+ free(rqp, M_NCPRQ);
+ return;
}
/*
* 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_TRYWAIT, 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 = m_getm(m, size, MT_DATA, M_TRYWAIT);
- 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 = m_getm(m, size, MT_DATA, M_TRYWAIT);
- 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;
+static int
+ncp_rq_pathstrhelp(struct mbchain *mbp, c_caddr_t src, caddr_t dst, int len)
+{
+ ncp_pathcopy(src, dst, len, mbp->mb_udata);
return 0;
}
int
-ncp_rq_mbuf(struct ncp_rq *rqp, struct mbuf *m, int size) {
+ncp_rq_pathstring(struct ncp_rq *rqp, int size, const char *name,
+ struct ncp_nlstables *nt)
+{
+ struct mbchain *mbp = &rqp->rq;
- 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;
+ mb_put_uint8(mbp, size);
+ mbp->mb_copy = ncp_rq_pathstrhelp;
+ mbp->mb_udata = nt;
+ return mb_put_mem(mbp, (c_caddr_t)name, size, MB_MCUSTOM);
}
-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;
+int
+ncp_rq_pstring(struct ncp_rq *rqp, const char *s)
+{
+ u_int len = strlen(s);
+ int error;
+
+ if (len > 255)
+ return EINVAL;
+ error = mb_put_uint8(&rqp->rq, len);
+ if (error)
+ return error;
+ return mb_put_mem(&rqp->rq, s, len, MB_MSYSTEM);
}
-void
+int
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)
{
+ struct mbchain *mbp = &rqp->rq;
int complen;
- ncp_rq_byte(rqp, vol_num);
- ncp_rq_dword(rqp, dir_base);
- ncp_rq_byte(rqp, 1); /* with dirbase */
+ mb_put_uint8(mbp, vol_num);
+ mb_put_mem(mbp, (c_caddr_t)&dir_base, sizeof(dir_base), MB_MSYSTEM);
+ mb_put_uint8(mbp, 1); /* with dirbase */
if (path != NULL && path[0]) {
if (namelen < 0) {
namelen = *path++;
- ncp_rq_byte(rqp, namelen);
+ mb_put_uint8(mbp, namelen);
for(; namelen; namelen--) {
complen = *path++;
- ncp_rq_byte(rqp, complen);
- ncp_rq_mem(rqp, path, complen);
+ mb_put_uint8(mbp, complen);
+ mb_put_mem(mbp, path, complen, MB_MSYSTEM);
path += complen;
}
} else {
- ncp_rq_byte(rqp, 1); /* 1 component */
+ mb_put_uint8(mbp, 1); /* 1 component */
ncp_rq_pathstring(rqp, namelen, path, nt);
}
} else {
- ncp_rq_byte(rqp, 0);
- ncp_rq_byte(rqp, 0);
+ mb_put_uint8(mbp, 0);
+ mb_put_uint8(mbp, 0);
}
+ return 0;
}
-/*
- * fetch reply routines
+
+/*
+ * Make a signature for the current packet and add it at the end of the
+ * packet.
*/
-#define ncp_mspaceleft (mtod(rqp->mrp,caddr_t)+rqp->mrp->m_len-rqp->bpos)
+static int
+ncp_sign_packet(struct ncp_conn *conn, struct ncp_rq *rqp, int *size)
+{
+ u_char data[64];
+ int error;
-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];
+ bzero(data, sizeof(data));
+ bcopy(conn->sign_root, data, 8);
+ setdle(data, 8, *size);
+ m_copydata(rqp->rq.mb_top, sizeof(struct ncp_rqhdr) - 1,
+ min((*size) - sizeof(struct ncp_rqhdr)+1, 52), data + 12);
+ ncp_sign(conn->sign_state, data, conn->sign_state);
+ error = mb_put_mem(&rqp->rq, (caddr_t)conn->sign_state, 8, MB_MSYSTEM);
+ if (error)
+ return error;
+ (*size) += 8;
+ return 0;
}
-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);
+/*
+ * Low level send rpc, here we do not attempt to restore any connection,
+ * Connection expected to be locked
+ */
+int
+ncp_request_int(struct ncp_rq *rqp)
+{
+ struct ncp_conn *conn = rqp->nr_conn;
+ struct proc *p = conn->procp;
+ struct socket *so = conn->ncp_so;
+ struct ncp_rqhdr *rq;
+ struct ncp_rphdr *rp=NULL;
+ struct timeval tv;
+ struct mbuf *m, *mreply = NULL;
+ struct mbchain *mbp;
+ int error, len, dosend, plen = 0, gotpacket;
+
+ if (conn->flags & NCPFL_INVALID)
+ return ENOTCONN;
+ if (so == NULL) {
+ printf("%s: ncp_so is NULL !\n",__FUNCTION__);
+ conn->flags |= NCPFL_INVALID;
+ return ENOTCONN;
}
- 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);
+ if (p == NULL)
+ p = curproc; /* XXX maybe procpage ? */
+ /*
+ * Flush out replies on previous reqs
+ */
+ while (ncp_poll(so, POLLIN) != 0) {
+ if (ncp_sock_recv(so, &m, &len) != 0)
+ break;
+ m_freem(m);
}
- togo = 0;
- while (rest--) {
- ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
+ mbp = &rqp->rq;
+ len = mb_fixhdr(mbp);
+ rq = mtod(mbp->mb_top, struct ncp_rqhdr *);
+ rq->seq = conn->seq;
+ m = rqp->rq.mb_top;
+
+ switch (rq->fn) {
+ case 0x15: case 0x16: case 0x17: case 0x23:
+ *(u_int16_t*)(rq + 1) = htons(len - 2 - sizeof(*rq));
+ break;
}
- 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++));
+ if (conn->flags & NCPFL_SIGNACTIVE) {
+ error = ncp_sign_packet(conn, rqp, &len);
+ if (error)
+ return error;
+ mbp->mb_top->m_pkthdr.len = len;
}
- 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);
+ 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;
+ error = 0;
+ for(dosend = 1;;) {
+ if (rqp->rexmit-- == 0) {
+ error = ETIMEDOUT;
+ break;
+ }
+ 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,
+ mbp->mb_top->m_pkthdr.len, rq->seq, rq->task
+ );
+ error = ncp_sock_send(so, mbp->mb_top, 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)
+ 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 || gotpacket)
+ break;
+ /* try to resend, or just wait */
}
- togo = 0;
- while (rest--) {
- ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
+ conn->seq++;
+ if (error) {
+ NCPSDEBUG("error=%d\n", error);
+ /*
+ * Any error except interruped call means that we have
+ * to reconnect. So, eliminate future timeouts by invalidating
+ * connection now.
+ */
+ if (error != EINTR)
+ conn->flags |= NCPFL_INVALID;
+ return (error);
}
- 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++));
+ if (conn->flags & NCPFL_SIGNACTIVE) {
+ /* XXX: check reply signature */
+ m_adj(mreply, -8);
+ plen -= 8;
}
- 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;
+ rp = mtod(mreply, struct ncp_rphdr*);
+ md_initm(&rqp->rp, mreply);
+ rqp->nr_rpsize = plen - sizeof(*rp);
+ rqp->nr_cc = error = rp->completion_code;
+ if (error)
+ error |= 0x8900; /* server error */
+ rqp->nr_cs = rp->connection_state;
+ if (rqp->nr_cs & (NCP_CS_BAD_CONN | NCP_CS_SERVER_DOWN)) {
+ NCPSDEBUG("server drop us\n");
+ conn->flags |= NCPFL_INVALID;
+ error = ECONNRESET;
}
- rqp->mrp=m;
- return;
+ md_get_mem(&rqp->rp, NULL, sizeof(*rp), MB_MSYSTEM);
+ return error;
}
-int
-ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size) {
- register struct mbuf *m=rqp->mrp;
- register unsigned count;
+/*
+ * Here we will try to restore any loggedin & dropped connection,
+ * connection should be locked on entry
+ */
+static __inline int
+ncp_restore_login(struct ncp_conn *conn)
+{
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_TRYWAIT);
- 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;
+ printf("ncprq: Restoring connection, flags = %x\n", conn->flags);
+ conn->flags &= ~(NCPFL_LOGGED | NCPFL_ATTACHED);
+ conn->flags |= NCPFL_RESTORING;
+ error = ncp_conn_reconnect(conn);
+ if (!error && (conn->flags & NCPFL_WASLOGGED))
+ error = ncp_login_object(conn, conn->li.user, conn->li.objtype, conn->li.password,conn->procp,conn->ucred);
+ if (error)
+ conn->flags |= NCPFL_INVALID;
+ conn->flags &= ~NCPFL_RESTORING;
+ return error;
}
int
-nwfs_mbuftouio(mrep, uiop, siz, dpos)
- struct mbuf **mrep;
- register struct uio *uiop;
- int siz;
- caddr_t *dpos;
+ncp_request(struct ncp_rq *rqp)
{
- 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;
+ struct ncp_conn *ncp = rqp->nr_conn;
+ int error, rcnt;
+
+ error = ncp_conn_lock(ncp, rqp->nr_p, rqp->nr_cred, NCPM_EXECUTE);
+ if (error)
+ goto out;
+ rcnt = NCP_RESTORE_COUNT;
+ for(;;) {
+ if ((ncp->flags & NCPFL_INVALID) == 0) {
+ error = ncp_request_int(rqp);
+ if ((ncp->flags & NCPFL_INVALID) == 0)
+ break;
}
- 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;
+ if (rcnt-- == 0) {
+ error = ECONNRESET;
+ break;
}
- 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_TRYWAIT, MT_DATA);
- if (clflg)
- MCLGET(mp, M_TRYWAIT);
- 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;
+ /*
+ * Do not attempt to restore connection recursively
+ */
+ if (ncp->flags & NCPFL_RESTORING) {
+ error = ENOTCONN;
+ break;
}
- uiop->uio_iov->iov_base += uiosiz;
- uiop->uio_iov->iov_len -= uiosiz;
- siz -= uiosiz;
+ error = ncp_restore_login(ncp);
+ if (error)
+ continue;
}
- *bpos = mtod(mp, caddr_t)+mp->m_len;
- *mq = mp;
- return (0);
+ ncp_conn_unlock(ncp, rqp->nr_p);
+out:
+ if (error && (rqp->nr_flags & NCPR_DONTFREEONERR) == 0)
+ ncp_rq_done(rqp);
+ return error;
}
OpenPOWER on IntegriCloud