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