static int smb_t2_reply(struct smb_t2rq *t2p) { struct mdchain *mdp; struct smb_rq *rqp = t2p->t2_rq; int error, totpgot, totdgot; u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp; u_int16_t tmp, bc, dcount; u_int8_t wc; error = smb_rq_reply(rqp); if (error) return error; if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) { /* * this is an interim response, ignore it. */ SMBRQ_SLOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_SUNLOCK(rqp); return 0; } /* * Now we have to get all subsequent responses. The CIFS specification * says that they can be disordered which is weird. * TODO: timo */ totpgot = totdgot = 0; totpcount = totdcount = 0xffff; mdp = &rqp->sr_rp; for (;;) { m_dumpm(mdp->md_top); if ((error = md_get_uint8(mdp, &wc)) != 0) break; if (wc < 10) { error = ENOENT; break; } if ((error = md_get_uint16le(mdp, &tmp)) != 0) break; if (totpcount > tmp) totpcount = tmp; md_get_uint16le(mdp, &tmp); if (totdcount > tmp) totdcount = tmp; if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */ (error = md_get_uint16le(mdp, &pcount)) != 0 || (error = md_get_uint16le(mdp, &poff)) != 0 || (error = md_get_uint16le(mdp, &pdisp)) != 0) break; if (pcount != 0 && pdisp != totpgot) { SMBERROR("Can't handle disordered parameters %d:%d\n", pdisp, totpgot); error = EINVAL; break; } if ((error = md_get_uint16le(mdp, &dcount)) != 0 || (error = md_get_uint16le(mdp, &doff)) != 0 || (error = md_get_uint16le(mdp, &ddisp)) != 0) break; if (dcount != 0 && ddisp != totdgot) { SMBERROR("Can't handle disordered data\n"); error = EINVAL; break; } md_get_uint8(mdp, &wc); md_get_uint8(mdp, NULL); tmp = wc; while (tmp--) md_get_uint16(mdp, NULL); if ((error = md_get_uint16le(mdp, &bc)) != 0) break; /* tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/ if (dcount) { error = smb_t2_placedata(mdp->md_top, doff, dcount, &t2p->t2_rdata); if (error) break; } if (pcount) { error = smb_t2_placedata(mdp->md_top, poff, pcount, &t2p->t2_rparam); if (error) break; } totpgot += pcount; totdgot += dcount; if (totpgot >= totpcount && totdgot >= totdcount) { error = 0; t2p->t2_flags |= SMBT2_ALLRECV; break; } /* * We're done with this reply, look for the next one. */ SMBRQ_SLOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_SUNLOCK(rqp); error = smb_rq_reply(rqp); if (error) break; } return error; }
static int smb_nt_reply(struct smb_ntrq *ntp) { struct mdchain *mdp; struct smb_rq *rqp = ntp->nt_rq; int error, error2; u_int32_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp; u_int32_t tmp, dcount, totpgot, totdgot; u_int16_t bc; u_int8_t wc; ntp->nt_flags &= ~SMBT2_MOREDATA; error = smb_rq_reply(rqp); if (rqp->sr_flags & SMBR_MOREDATA) ntp->nt_flags |= SMBT2_MOREDATA; ntp->nt_sr_error = rqp->sr_error; ntp->nt_sr_rpflags2 = rqp->sr_rpflags2; if (error && !(rqp->sr_flags & SMBR_MOREDATA)) return (error); /* * Now we have to get all subseqent responses. The CIFS specification * says that they can be misordered which is weird. * TODO: timo */ totpgot = totdgot = 0; totpcount = totdcount = 0xffffffff; mdp = &rqp->sr_rp; for (;;) { DTRACE_PROBE2(smb_trans_reply, (smb_rq_t *), rqp, (mblk_t *), mdp->md_top); m_dumpm(mdp->md_top); if ((error2 = md_get_uint8(mdp, &wc)) != 0) break; if (wc < 18) { error2 = ENOENT; break; } md_get_mem(mdp, NULL, 3, MB_MSYSTEM); /* reserved */ if ((error2 = md_get_uint32le(mdp, &tmp)) != 0) break; if (totpcount > tmp) totpcount = tmp; if ((error2 = md_get_uint32le(mdp, &tmp)) != 0) break; if (totdcount > tmp) totdcount = tmp; if ((error2 = md_get_uint32le(mdp, &pcount)) != 0 || (error2 = md_get_uint32le(mdp, &poff)) != 0 || (error2 = md_get_uint32le(mdp, &pdisp)) != 0) break; if (pcount != 0 && pdisp != totpgot) { SMBSDEBUG("Can't handle misordered parameters %d:%d\n", pdisp, totpgot); error2 = EINVAL; break; } if ((error2 = md_get_uint32le(mdp, &dcount)) != 0 || (error2 = md_get_uint32le(mdp, &doff)) != 0 || (error2 = md_get_uint32le(mdp, &ddisp)) != 0) break; if (dcount != 0 && ddisp != totdgot) { SMBSDEBUG("Can't handle misordered data: dcount %d\n", dcount); error2 = EINVAL; break; } /* XXX: Skip setup words? We don't save them? */ md_get_uint8(mdp, &wc); /* SetupCount */ tmp = wc; while (tmp--) md_get_uint16le(mdp, NULL); if ((error2 = md_get_uint16le(mdp, &bc)) != 0) break; /* * There are pad bytes here, and the poff value * indicates where the next data are found. * No need to guess at the padding size. */ if (pcount) { error2 = smb_t2_placedata(mdp->md_top, poff, pcount, &ntp->nt_rparam); if (error2) break; } totpgot += pcount; if (dcount) { error2 = smb_t2_placedata(mdp->md_top, doff, dcount, &ntp->nt_rdata); if (error2) break; } totdgot += dcount; if (totpgot >= totpcount && totdgot >= totdcount) { error2 = 0; ntp->nt_flags |= SMBT2_ALLRECV; break; } /* * We're done with this reply, look for the next one. */ SMBRQ_LOCK(rqp); md_next_record(&rqp->sr_rp); SMBRQ_UNLOCK(rqp); error2 = smb_rq_reply(rqp); if (rqp->sr_flags & SMBR_MOREDATA) ntp->nt_flags |= SMBT2_MOREDATA; if (!error2) continue; ntp->nt_sr_error = rqp->sr_error; ntp->nt_sr_rpflags2 = rqp->sr_rpflags2; error = error2; if (!(rqp->sr_flags & SMBR_MOREDATA)) break; } return (error ? error : error2); }