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; }
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; }
/* * 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; }