Beispiel #1
0
static void
ncp_watchdog(struct ncp_conn *conn) {
	char *buf;
	struct mbuf *m;
	int error, len, flags;
	struct socket *so;
	struct sockaddr *sa;
	struct uio auio;

	sa = NULL;
	while (conn->wdg_so) { /* not a loop */
		so = conn->wdg_so;
		auio.uio_resid = len = 1000000;
		auio.uio_td = curthread;
		flags = MSG_DONTWAIT;
		error = soreceive(so, (struct sockaddr**)&sa, &auio, &m,
		    (struct mbuf**)0, &flags);
		if (error) break;
		len -= auio.uio_resid;
		NCPSDEBUG("got watch dog %d\n",len);
		if (len != 2) break;
		buf = mtod(m, char*);
		if (buf[1] != '?') break;
		buf[1] = 'Y';
		error = sosend(so, (struct sockaddr*)sa, 0, m, 0, 0, curthread);
		NCPSDEBUG("send watch dog %d\n",error);
		break;
	}
	if (sa) free(sa, M_SONAME);
	return;
}
Beispiel #2
0
static void
ncp_watchdog(struct ncp_conn *conn) {
	char *buf;
	int error, len, flags;
	struct socket *so;
	struct sockaddr *sa;
	struct sockbuf sio;

	sa = NULL;
	while (conn->wdg_so) { /* not a loop */
		so = conn->wdg_so;
		sbinit(&sio, 1000000);
		flags = MSG_DONTWAIT;
		error = so_pru_soreceive(so, (struct sockaddr**)&sa,
					 NULL, &sio, NULL, &flags);
		if (error)
			break;
		len = sio.sb_cc;
		NCPSDEBUG("got watch dog %d\n",len);
		if (len != 2) {
			m_freem(sio.sb_mb);
			break;
		}
		buf = mtod(sio.sb_mb, char *);
		if (buf[1] != '?') {
			m_freem(sio.sb_mb);
			break;
		}
		buf[1] = 'Y';
		error = so_pru_sosend(so, sa, NULL, sio.sb_mb, NULL, 0, curthread);
		NCPSDEBUG("send watch dog %d\n",error);
		break;
	}
	if (sa)
		kfree(sa, M_SONAME);
	return;
}
Beispiel #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;
}