/* * Routines for fetching data from an mbuf chain */ int md_init(struct mdchain *mdp) { struct mbuf *m; m = m_gethdr(M_WAIT, MT_DATA); m->m_len = 0; md_initm(mdp, m); return 0; }
/* * Routines for fetching data from an mbuf chain */ int md_init(struct mdchain *mdp) { struct mbuf *m; m = m_gethdr(M_WAIT, MT_DATA); if (m == NULL) return ENOBUFS; m->m_len = 0; md_initm(mdp, m); return 0; }
/* * Put next record in place of existing */ int md_next_record(struct mdchain *mdp) { struct mbuf *m; if (mdp->md_top == NULL) return ENOENT; m = mdp->md_top->m_nextpkt; md_done(mdp); if (m == NULL) return ENOENT; md_initm(mdp, m); return 0; }
static int smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count, struct mdchain *mdp) { struct mbuf *m, *m0; int len; m0 = m_split(mtop, offset, M_WAIT); len = m_length(m0, &m); m->m_len -= len - count; if (mdp->md_top == NULL) { md_initm(mdp, m0); } else m_cat(mdp->md_top, m0); return 0; }
/* * Append a separate mbuf chain. It is caller responsibility to prevent * multiple calls to fetch/record routines. */ void md_append_record(struct mdchain *mdp, struct mbuf *top) { struct mbuf *m; if (mdp->md_top == NULL) { md_initm(mdp, top); return; } m = mdp->md_top; while (m->m_nextpkt) m = m->m_nextpkt; m->m_nextpkt = top; top->m_nextpkt = NULL; return; }
/* * Extract data [offset,count] from mtop and add to mdp. */ static int smb_t2_placedata(mblk_t *mtop, u_int16_t offset, u_int16_t count, struct mdchain *mdp) { mblk_t *n; n = m_copym(mtop, offset, count, M_WAITOK); if (n == NULL) return (EBADRPC); if (mdp->md_top == NULL) { md_initm(mdp, n); } else m_cat(mdp->md_top, n); return (0); }
static int smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count, struct mdchain *mdp) { struct mbuf *m, *m0; int len; m0 = m_split(mtop, offset, M_WAIT); if (m0 == NULL) return EBADRPC; for(len = 0, m = m0; m->m_next; m = m->m_next) len += m->m_len; len += m->m_len; m->m_len -= len - count; if (mdp->md_top == NULL) { md_initm(mdp, m0); } else m_cat(mdp->md_top, m0); return 0; }
/* * Perform a full round of TRANS2 request */ static int smb_t2_request_int(struct smb_t2rq *t2p) { struct smb_vc *vcp = t2p->t2_vc; struct smb_cred *scred = t2p->t2_cred; struct mbchain *mbp; struct mdchain *mdp, mbparam, mbdata; struct mbuf *m; struct smb_rq *rqp; int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i; int error, doff, poff, txdcount, txpcount, nmlen; m = t2p->t2_tparam.mb_top; if (m) { md_initm(&mbparam, m); /* do not free it! */ totpcount = m_fixhdr(m); if (totpcount > 0xffff) /* maxvalue for u_short */ return EINVAL; } else totpcount = 0; m = t2p->t2_tdata.mb_top; if (m) { md_initm(&mbdata, m); /* do not free it! */ totdcount = m_fixhdr(m); if (totdcount > 0xffff) return EINVAL; } else totdcount = 0; leftdcount = totdcount; leftpcount = totpcount; txmax = vcp->vc_txmax; error = smb_rq_alloc(t2p->t2_source, t2p->t_name ? SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp); if (error) return error; rqp->sr_flags |= SMBR_MULTIPACKET; t2p->t2_rq = rqp; rqp->sr_t2 = t2p; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); mb_put_uint16le(mbp, t2p->t2_maxpcount); mb_put_uint16le(mbp, t2p->t2_maxdcount); mb_put_uint8(mbp, t2p->t2_maxscount); mb_put_uint8(mbp, 0); /* reserved */ mb_put_uint16le(mbp, 0); /* flags */ mb_put_uint32le(mbp, 0); /* Timeout */ mb_put_uint16le(mbp, 0); /* reserved 2 */ len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1), * and need to decide which parts should go into the first request */ nmlen = t2p->t_name ? strlen(t2p->t_name) : 0; len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } leftpcount -= txpcount; leftdcount -= txdcount; mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint8(mbp, t2p->t2_setupcount); mb_put_uint8(mbp, 0); for (i = 0; i < t2p->t2_setupcount; i++) mb_put_uint16le(mbp, t2p->t2_setupdata[i]); smb_rq_wend(rqp); smb_rq_bstart(rqp); /* TDUNICODE */ if (t2p->t_name) mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM); mb_put_uint8(mbp, 0); /* terminating zero */ len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto freerq; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); /* incredible, but thats it... */ error = smb_rq_enqueue(rqp); if (error) goto freerq; if (leftpcount == 0 && leftdcount == 0) t2p->t2_flags |= SMBT2_ALLSENT; error = smb_t2_reply(t2p); if (error) goto bad; while (leftpcount || leftdcount) { t2p->t2_flags |= SMBT2_SECONDARY; error = smb_rq_new(rqp, t2p->t_name ? SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY); if (error) goto bad; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one, * and need to decide which parts should go into request */ len = ALIGN4(len + 6 * 2 + 2); if (t2p->t_name == NULL) len += 2; if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, totpcount - leftpcount); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint16le(mbp, totdcount - leftdcount); leftpcount -= txpcount; leftdcount -= txdcount; if (t2p->t_name == NULL) mb_put_uint16le(mbp, t2p->t2_fid); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, 0); /* name */ len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); rqp->sr_state = SMBRQ_NOTSENT; error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL); if (error) goto bad; } /* while left params or data */ t2p->t2_flags |= SMBT2_ALLSENT; mdp = &t2p->t2_rdata; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &t2p->t2_rparam; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: smb_iod_removerq(rqp); freerq: smb_rq_done(rqp); if (error) { if (rqp->sr_flags & SMBR_RESTART) t2p->t2_flags |= SMBT2_RESTART; md_done(&t2p->t2_rparam); md_done(&t2p->t2_rdata); } 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; }
/* * Perform a full round of TRANS2 request */ static int smb_t2_request_int(struct smb_t2rq *t2p) { struct smb_vc *vcp = t2p->t2_vc; struct smb_cred *scred = t2p->t2_cred; struct mbchain *mbp; struct mdchain *mdp, mbparam, mbdata; mblk_t *m; struct smb_rq *rqp; int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i; int error, doff, poff, txdcount, txpcount, nmlen, nmsize; m = t2p->t2_tparam.mb_top; if (m) { md_initm(&mbparam, m); /* do not free it! */ totpcount = m_fixhdr(m); if (totpcount > 0xffff) /* maxvalue for ushort_t */ return (EINVAL); } else totpcount = 0; m = t2p->t2_tdata.mb_top; if (m) { md_initm(&mbdata, m); /* do not free it! */ totdcount = m_fixhdr(m); if (totdcount > 0xffff) return (EINVAL); } else totdcount = 0; leftdcount = totdcount; leftpcount = totpcount; txmax = vcp->vc_txmax; error = smb_rq_alloc(t2p->t2_source, t2p->t_name ? SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp); if (error) return (error); rqp->sr_timo = smb_timo_default; rqp->sr_flags |= SMBR_MULTIPACKET; t2p->t2_rq = rqp; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); mb_put_uint16le(mbp, t2p->t2_maxpcount); mb_put_uint16le(mbp, t2p->t2_maxdcount); mb_put_uint8(mbp, t2p->t2_maxscount); mb_put_uint8(mbp, 0); /* reserved */ mb_put_uint16le(mbp, 0); /* flags */ mb_put_uint32le(mbp, 0); /* Timeout */ mb_put_uint16le(mbp, 0); /* reserved 2 */ len = mb_fixhdr(mbp); /* * Now we know the size of the trans overhead stuff: * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + nmsize), * where nmsize is the OTW size of the name, including * the unicode null terminator and any alignment. * Use this to decide which parts (and how much) * can go into this request: params, data */ nmlen = t2p->t_name ? t2p->t_name_len : 0; nmsize = nmlen + 1; /* null term. */ if (SMB_UNICODE_STRINGS(vcp)) { nmsize *= 2; /* we know put_dmem will need to align */ nmsize += 1; } len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmsize); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; /* * Other client traffic seems to "ALIGN2" here. The extra * 2 byte pad we use has no observed downside and may be * required for some old servers(?) */ len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } leftpcount -= txpcount; leftdcount -= txdcount; mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint8(mbp, t2p->t2_setupcount); mb_put_uint8(mbp, 0); for (i = 0; i < t2p->t2_setupcount; i++) { mb_put_uint16le(mbp, t2p->t2_setupdata[i]); } smb_rq_wend(rqp); smb_rq_bstart(rqp); if (t2p->t_name) { /* Put the string and terminating null. */ smb_put_dmem(mbp, vcp, t2p->t_name, nmlen + 1, SMB_CS_NONE, NULL); } else { /* nmsize accounts for padding, char size. */ mb_put_mem(mbp, NULL, nmsize, MB_MZERO); } len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto freerq; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); /* incredible, but thats it... */ error = smb_rq_enqueue(rqp); if (error) goto freerq; if (leftpcount || leftdcount) { error = smb_rq_reply(rqp); if (error) goto bad; /* * this is an interim response, ignore it. */ SMBRQ_LOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_UNLOCK(rqp); } while (leftpcount || leftdcount) { error = smb_rq_new(rqp, t2p->t_name ? SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY); if (error) goto bad; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint16le(mbp, totpcount); mb_put_uint16le(mbp, totdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one, * and need to decide which parts should go into request */ len = ALIGN4(len + 6 * 2 + 2); if (t2p->t_name == NULL) len += 2; if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } mb_put_uint16le(mbp, txpcount); mb_put_uint16le(mbp, poff); mb_put_uint16le(mbp, totpcount - leftpcount); mb_put_uint16le(mbp, txdcount); mb_put_uint16le(mbp, doff); mb_put_uint16le(mbp, totdcount - leftdcount); leftpcount -= txpcount; leftdcount -= txdcount; if (t2p->t_name == NULL) mb_put_uint16le(mbp, t2p->t2_fid); smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, 0); /* name */ len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); error = smb_iod_multirq(rqp); if (error) goto bad; } /* while left params or data */ error = smb_t2_reply(t2p); if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) goto bad; mdp = &t2p->t2_rdata; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &t2p->t2_rparam; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: smb_iod_removerq(rqp); freerq: if (error && !(t2p->t2_flags & SMBT2_MOREDATA)) { if (rqp->sr_flags & SMBR_RESTART) t2p->t2_flags |= SMBT2_RESTART; md_done(&t2p->t2_rparam); md_done(&t2p->t2_rdata); } smb_rq_done(rqp); return (error); }
/* * Perform a full round of NT_TRANSACTION request */ static int smb_nt_request_int(struct smb_ntrq *ntp) { struct smb_vc *vcp = ntp->nt_vc; struct smb_cred *scred = ntp->nt_cred; struct mbchain *mbp; struct mdchain *mdp, mbsetup, mbparam, mbdata; mblk_t *m; struct smb_rq *rqp; int totpcount, leftpcount, totdcount, leftdcount, len, txmax; int error, doff, poff, txdcount, txpcount; int totscount; m = ntp->nt_tsetup.mb_top; if (m) { md_initm(&mbsetup, m); /* do not free it! */ totscount = m_fixhdr(m); if (totscount > 2 * 0xff) return (EINVAL); } else totscount = 0; m = ntp->nt_tparam.mb_top; if (m) { md_initm(&mbparam, m); /* do not free it! */ totpcount = m_fixhdr(m); if (totpcount > 0x7fffffff) return (EINVAL); } else totpcount = 0; m = ntp->nt_tdata.mb_top; if (m) { md_initm(&mbdata, m); /* do not free it! */ totdcount = m_fixhdr(m); if (totdcount > 0x7fffffff) return (EINVAL); } else totdcount = 0; leftdcount = totdcount; leftpcount = totpcount; txmax = vcp->vc_txmax; error = smb_rq_alloc(ntp->nt_source, SMB_COM_NT_TRANSACT, scred, &rqp); if (error) return (error); rqp->sr_timo = smb_timo_default; rqp->sr_flags |= SMBR_MULTIPACKET; ntp->nt_rq = rqp; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_uint8(mbp, ntp->nt_maxscount); mb_put_uint16le(mbp, 0); /* reserved (flags?) */ mb_put_uint32le(mbp, totpcount); mb_put_uint32le(mbp, totdcount); mb_put_uint32le(mbp, ntp->nt_maxpcount); mb_put_uint32le(mbp, ntp->nt_maxdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2), * and need to decide which parts should go into the first request */ len = ALIGN4(len + 4 * 4 + 1 + 2 + ((totscount+1)&~1) + 2); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } leftpcount -= txpcount; leftdcount -= txdcount; mb_put_uint32le(mbp, txpcount); mb_put_uint32le(mbp, poff); mb_put_uint32le(mbp, txdcount); mb_put_uint32le(mbp, doff); mb_put_uint8(mbp, (totscount+1)/2); mb_put_uint16le(mbp, ntp->nt_function); if (totscount) { error = md_get_mbuf(&mbsetup, totscount, &m); SMBSDEBUG("%d:%d:%d\n", error, totscount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); if (totscount & 1) mb_put_uint8(mbp, 0); /* setup is in words */ } smb_rq_wend(rqp); smb_rq_bstart(rqp); len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax); if (error) goto freerq; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto freerq; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); /* incredible, but thats it... */ error = smb_rq_enqueue(rqp); if (error) goto freerq; if (leftpcount || leftdcount) { error = smb_rq_reply(rqp); if (error) goto bad; /* * this is an interim response, ignore it. */ SMBRQ_LOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_UNLOCK(rqp); } while (leftpcount || leftdcount) { error = smb_rq_new(rqp, SMB_COM_NT_TRANSACT_SECONDARY); if (error) goto bad; mbp = &rqp->sr_rq; smb_rq_wstart(rqp); mb_put_mem(mbp, NULL, 3, MB_MZERO); mb_put_uint32le(mbp, totpcount); mb_put_uint32le(mbp, totdcount); len = mb_fixhdr(mbp); /* * now we have known packet size as * ALIGN4(len + 6 * 4 + 2) * and need to decide which parts should go into request */ len = ALIGN4(len + 6 * 4 + 2); if (len + leftpcount > txmax) { txpcount = min(leftpcount, txmax - len); poff = len; txdcount = 0; doff = 0; } else { txpcount = leftpcount; poff = txpcount ? len : 0; len = ALIGN4(len + txpcount); txdcount = min(leftdcount, txmax - len); doff = txdcount ? len : 0; } mb_put_uint32le(mbp, txpcount); mb_put_uint32le(mbp, poff); mb_put_uint32le(mbp, totpcount - leftpcount); mb_put_uint32le(mbp, txdcount); mb_put_uint32le(mbp, doff); mb_put_uint32le(mbp, totdcount - leftdcount); leftpcount -= txpcount; leftdcount -= txdcount; smb_rq_wend(rqp); smb_rq_bstart(rqp); len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbparam, txpcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } len = mb_fixhdr(mbp); if (txdcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); error = md_get_mbuf(&mbdata, txdcount, &m); if (error) goto bad; mb_put_mbuf(mbp, m); } smb_rq_bend(rqp); error = smb_iod_multirq(rqp); if (error) goto bad; } /* while left params or data */ error = smb_nt_reply(ntp); if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) goto bad; mdp = &ntp->nt_rdata; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &ntp->nt_rparam; if (mdp->md_top) { m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: smb_iod_removerq(rqp); freerq: if (error && !(ntp->nt_flags & SMBT2_MOREDATA)) { if (rqp->sr_flags & SMBR_RESTART) ntp->nt_flags |= SMBT2_RESTART; md_done(&ntp->nt_rparam); md_done(&ntp->nt_rdata); } smb_rq_done(rqp); return (error); }
static int userfw_sosend(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr_, struct mbuf *control, struct thread *td) { int err = 0; struct userfwpcb *pcb = sotopcb(so); struct userfw_io_header msg; int cmd_ready = 0; unsigned char *data = NULL; struct mdchain chain; if (pcb == NULL) err = ENOTCONN; if (control != NULL) err = EINVAL; SOCKBUF_LOCK(&(so->so_snd)); if (err == 0) { sbappendstream_locked(&(so->so_snd), m); m = NULL; md_initm(&chain, so->so_snd.sb_mb); if (SOCKBUF_LEN(so->so_snd) >= sizeof(msg)) { md_get_mem(&chain, (caddr_t)(&msg), sizeof(msg), MB_MSYSTEM); if (SOCKBUF_LEN(so->so_snd) >= msg.length) cmd_ready = 1; } } if (err == 0 && cmd_ready) { if (msg.type != T_CONTAINER || (msg.subtype != ST_MESSAGE && msg.subtype != ST_CMDCALL)) { cmd_ready = 0; sbdrop_locked(&(so->so_snd), msg.length); } } if (err == 0 && cmd_ready) { data = malloc(msg.length, M_USERFW, M_WAITOK); md_initm(&chain, so->so_snd.sb_mb); md_get_mem(&chain, data, msg.length, MB_MSYSTEM); err = userfw_cmd_dispatch(data, so, td); sbdrop_locked(&(so->so_snd), msg.length); free(data, M_USERFW); } SOCKBUF_UNLOCK(&(so->so_snd)); if (control != NULL) m_freem(control); if (m != NULL) m_freem(m); return err; }