Exemple #1
0
int
ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp)
{
	struct thread *td = curthread; /* XXX */
	struct sockaddr *to = 0;
	struct ncp_conn *conn = rqp->nr_conn;
	struct mbuf *m;
	int error, flags=0;

	for (;;) {
		m = m_copym(top, 0, M_COPYALL, M_WAIT);
/*		NCPDDEBUG(m);*/
		error = sosend(so, to, 0, m, 0, flags, td);
		if (error == 0 || error == EINTR || error == ENETDOWN)
			break;
		if (rqp->rexmit == 0) break;
		rqp->rexmit--;
		pause("ncprsn", conn->li.timeout * hz);
		error = ncp_chkintr(conn, td);
		if (error == EINTR) break;
	}
	if (error) {
		log(LOG_INFO, "ncp_send: error %d for server %s", error, conn->li.server);
	}
	return error;
}
Exemple #2
0
/*
 * Flush and invalidate all dirty buffers. If another process is already
 * doing the flush, just wait for completion.
 */
int
nwfs_vinvalbuf(struct vnode *vp, int flags, int intrflg)
{
	struct nwnode *np = VTONW(vp);
/*	struct nwmount *nmp = VTONWFS(vp);*/
	int error = 0, slpflag, slptimeo;

	if (vp->v_flag & VRECLAIMED) {
		return (0);
	}
	if (intrflg) {
		slpflag = PCATCH;
		slptimeo = 2 * hz;
	} else {
		slpflag = 0;
		slptimeo = 0;
	}
	while (np->n_flag & NFLUSHINPROG) {
		np->n_flag |= NFLUSHWANT;
		error = tsleep((caddr_t)&np->n_flag, 0, "nwfsvinv", slptimeo);
		error = ncp_chkintr(NWFSTOCONN(VTONWFS(vp)), curthread);
		if (error == EINTR && intrflg)
			return EINTR;
	}
	np->n_flag |= NFLUSHINPROG;
	error = vinvalbuf(vp, flags, slpflag, 0);
	while (error) {
		if (intrflg && (error == ERESTART || error == EINTR)) {
			np->n_flag &= ~NFLUSHINPROG;
			if (np->n_flag & NFLUSHWANT) {
				np->n_flag &= ~NFLUSHWANT;
				wakeup((caddr_t)&np->n_flag);
			}
			return EINTR;
		}
		error = vinvalbuf(vp, flags, slpflag, 0);
	}
	np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
	if (np->n_flag & NFLUSHWANT) {
		np->n_flag &= ~NFLUSHWANT;
		wakeup((caddr_t)&np->n_flag);
	}
	return (error);
}
Exemple #3
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 thread *td = conn->td;
	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 (so == NULL) {
		printf("%s: ncp_so is NULL !\n",__func__);
		ncp_conn_invalidate(conn);
		return ENOTCONN;
	}
	if (td == NULL)
		td = curthread;	/* XXX maybe procpage ? */
	/*
	 * Flush out replies on previous reqs
	 */
	tv.tv_sec = 0;
	tv.tv_usec = 0;
	while (selsocket(so, POLLIN, &tv, td) == 0) {
		if (ncp_sock_recv(so, &m, &len) != 0)
			break;
		m_freem(m);
	}
	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;
	}
	if (conn->flags & NCPFL_SIGNACTIVE) {
		error = ncp_sign_packet(conn, rqp, &len);
		if (error)
			return error;
		mbp->mb_top->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;
	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 = selsocket(so, POLLIN, &tv, td);
		if (error == EWOULDBLOCK )	/* timeout expired */
			continue;
		error = ncp_chkintr(conn, td);
		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;
			tv.tv_sec = 0;
			tv.tv_usec = 0;
			if (selsocket(so, POLLIN, &tv, td) != 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",__func__);
					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 */
	}
	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)
			ncp_conn_invalidate(conn);
		return (error);
	}
	if (conn->flags & NCPFL_SIGNACTIVE) {
		/* XXX: check reply signature */
		m_adj(mreply, -8);
		plen -= 8;
	}
	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");
		ncp_conn_invalidate(conn);
		error = ECONNRESET;
	}
	md_get_mem(&rqp->rp, NULL, sizeof(*rp), MB_MSYSTEM);
	return error;
}