/*
* Copyright (c) 2000-2001, Boris Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: smb_rq.c,v 1.29 2005/02/11 01:44:17 lindak Exp $
*/
/*
*/
#include <netsmb/smb_osdep.h>
#include <netsmb/smb_conn.h>
#include <netsmb/smb_subr.h>
#include <netsmb/smb_tran.h>
/*
* How long to wait before restarting a request (after reconnect)
*/
/*
* leave this zero - we can't ssecond guess server side effects of
* duplicate ops, this isn't nfs!
*/
#define SMBMAXRESTARTS 0
/*
* Done with a request object. Free its contents.
* If it was allocated (SMBR_ALLOCED) free it too.
* Some of these are stack locals, not allocated.
*
* No locks here - this is the last ref.
*/
void
{
/*
* No smb_vc_rele() here - see smb_rq_init()
*/
}
int
{
int error;
return (ENOMEM);
if (error) {
return (error);
}
return (0);
}
int
{
int error;
if (error)
return (error);
/*
* We copied a VC pointer (vcp) into rqp->sr_vc,
* but we do NOT do a smb_vc_hold here. Instead,
* the caller is responsible for the hold on the
* share or the VC as needed. For smbfs callers,
* the hold is on the share, via the smbfs mount.
* For nsmb ioctl callers, the hold is done when
* the driver handle gets VC or share references.
* when creating and completing requests.
*/
return (error);
}
static int
{
int error;
rqp->sr_sendcnt = 0;
if (error)
return (error);
/*
* Is this the right place to save the flags?
*/
/*
* The SMB header is filled in later by
* smb_rq_fillhdr (see below)
* Just reserve space here.
*/
return (0);
}
/*
* Given a request with it's body already composed,
* rewind to the start and fill in the SMB header.
* This is called after the request is enqueued,
* so we have the final MID, seq num. etc.
*/
void
{
mblk_t *m;
/*
* Fill in the SMB header using a dup of the first mblk,
* which points at the same data but has its own wptr,
* so we can rewind without trashing the message.
*/
/* This will free the mblk from dupb. */
}
int
{
}
/*
* Simple request-reply exchange
*/
int
{
for (; ; ) {
/*
* Don't send any new requests if force unmount is underway.
* This check was moved into smb_rq_enqueue.
*/
if (error) {
break;
}
if (!error)
break;
break;
break;
} else {
}
}
return (error);
}
static int
{
int error = 0;
/*
* Normal requests may initiate a reconnect,
* Some requests set the NORECONNECT flag
* to avoid all that (i.e. tree discon)
*/
return (ENOTCONN);
}
return (ENOTCONN);
goto ok_out;
}
/*
* If we're not connected, initiate a reconnect
*/
if (error != 0)
return (error);
}
/*
* If this request has a "share" object
* that needs a tree connect, do it now.
*/
if (error)
return (error);
}
/*
* We now know what UID + TID to use.
* Store them in the request.
*/
return (error);
}
/*
* Mark location of the word count, which is filled in later by
* smb_rw_wend(). Also initialize the counter that it uses
* to figure out what value to fill in.
*
* Note that the word count happens to be 8-bit.
*/
void
{
}
void
{
SMBSDEBUG("no wcount\n");
return;
}
if (wcnt > 0x1ff)
if (wcnt & 1)
SMBSDEBUG("odd word count\n");
/* Fill in the word count (8-bits) */
}
/*
* Mark location of the byte count, which is filled in later by
* smb_rw_bend(). Also initialize the counter that it uses
* to figure out what value to fill in.
*
* Note that the byte count happens to be 16-bit.
*/
void
{
}
void
{
SMBSDEBUG("no bcount\n");
return;
}
if (bcnt > 0xffff)
/*
* Fill in the byte count (16-bits)
* The pointer is char * type due to
* typical off-by-one alignment.
*/
}
int
{
return (EINTR);
return (0);
}
static int
{
SMBSDEBUG("zombie CO\n");
goto out;
}
case SMBL_SHARE:
break;
}
/* instead of recursion... */
/* FALLTHROUGH */
case SMBL_VC:
break;
}
error = 0;
break;
default:
}
out:
if (!error) {
if (vcpp)
if (sspp)
}
return (error);
}
/*
* Wait for reply on the request
*/
static int
{
return (0);
}
if (error)
return (error);
/*
* If the request was signed, validate the
* signature on the response.
*/
if (error)
return (error);
}
/*
* Parse the SMB header
*/
if (error)
return (error);
/*
* Do a special check for STATUS_BUFFER_OVERFLOW;
* it's not an error.
*/
/*
* Don't report it as an error to our caller;
* they can look at rqp->sr_error if they
* need to know whether we got a
* STATUS_BUFFER_OVERFLOW.
* XXX - should we do that for all errors
* where (error & 0xC0000000) is 0x80000000,
* i.e. all warnings?
*/
rperror = 0;
} else
} else {
}
} else
}
/*
* TRANS2 request implementation
* TRANS implementation is in the "t2" routines
* NT_TRANSACTION implementation is the separate "nt" stuff
*/
int
{
int error;
return (ENOMEM);
if (error) {
return (error);
}
return (0);
}
int
{
int error;
return (ENOMEM);
if (error) {
return (error);
}
return (0);
}
int
{
int i;
int error;
for (i = 0; i < setupcnt; i++)
if (error)
return (error);
return (0);
}
int
{
int error;
if (error)
return (error);
return (0);
}
void
{
}
void
{
}
/*
* Extract data [offset,count] from mtop and add to mdp.
*/
static int
{
mblk_t *n;
if (n == NULL)
return (EBADRPC);
} else
return (0);
}
static int
{
return (error);
/*
* Now we have to get all subseqent responses, if any.
* The CIFS specification says that they can be misordered,
* which is weird.
* TODO: timo
*/
for (;;) {
break;
if (wc < 10) {
break;
}
break;
break;
break;
SMBSDEBUG("Can't handle misordered parameters %d:%d\n",
break;
}
break;
SMBSDEBUG("Can't handle misordered data: dcount %d\n",
dcount);
break;
}
/* XXX: Skip setup words? We don't save them? */
while (tmp--)
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) {
if (error2)
break;
}
if (dcount) {
if (error2)
break;
}
error2 = 0;
break;
}
/*
* We're done with this reply, look for the next one.
*/
if (!error2)
continue;
break;
}
}
static int
{
return (error);
/*
* Now we have to get all subseqent responses. The CIFS specification
* says that they can be misordered which is weird.
* TODO: timo
*/
for (;;) {
break;
if (wc < 18) {
break;
}
break;
break;
break;
SMBSDEBUG("Can't handle misordered parameters %d:%d\n",
break;
}
break;
SMBSDEBUG("Can't handle misordered data: dcount %d\n",
dcount);
break;
}
/* XXX: Skip setup words? We don't save them? */
while (tmp--)
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) {
if (error2)
break;
}
if (dcount) {
if (error2)
break;
}
error2 = 0;
break;
}
/*
* We're done with this reply, look for the next one.
*/
if (!error2)
continue;
break;
}
}
/*
* Perform a full round of TRANS2 request
*/
static int
{
mblk_t *m;
if (m) {
return (EINVAL);
} else
totpcount = 0;
if (m) {
if (totdcount > 0xffff)
return (EINVAL);
} else
totdcount = 0;
if (error)
return (error);
/*
* 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
*/
if (SMB_UNICODE_STRINGS(vcp)) {
nmsize *= 2;
/* we know put_dmem will need to align */
nmsize += 1;
}
txdcount = 0;
doff = 0;
} else {
/*
* 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(?)
*/
}
leftpcount -= txpcount;
leftdcount -= txdcount;
mb_put_uint8(mbp, 0);
for (i = 0; i < t2p->t2_setupcount; i++) {
}
/* Put the string and terminating null. */
SMB_CS_NONE, NULL);
} else {
/* nmsize accounts for padding, char size. */
}
if (error)
goto freerq;
if (txpcount) {
if (error)
goto freerq;
mb_put_mbuf(mbp, m);
}
if (txdcount) {
if (error)
goto freerq;
mb_put_mbuf(mbp, m);
}
if (error)
goto freerq;
if (leftpcount || leftdcount) {
if (error)
goto bad;
/*
* this is an interim response, ignore it.
*/
}
while (leftpcount || leftdcount) {
if (error)
goto bad;
/*
* 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 += 2;
txdcount = 0;
doff = 0;
} else {
}
leftpcount -= txpcount;
leftdcount -= txdcount;
if (txpcount) {
if (error)
goto bad;
mb_put_mbuf(mbp, m);
}
if (txdcount) {
if (error)
goto bad;
mb_put_mbuf(mbp, m);
}
if (error)
goto bad;
} /* while left params or data */
goto bad;
}
}
bad:
}
return (error);
}
/*
* Perform a full round of NT_TRANSACTION request
*/
static int
{
mblk_t *m;
int totscount;
if (m) {
return (EINVAL);
} else
totscount = 0;
if (m) {
if (totpcount > 0x7fffffff)
return (EINVAL);
} else
totpcount = 0;
if (m) {
if (totdcount > 0x7fffffff)
return (EINVAL);
} else
totdcount = 0;
if (error)
return (error);
/*
* 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
*/
txdcount = 0;
doff = 0;
} else {
}
leftpcount -= txpcount;
leftdcount -= txdcount;
if (totscount) {
if (error)
goto freerq;
mb_put_mbuf(mbp, m);
if (totscount & 1)
}
if (txpcount) {
if (error)
goto freerq;
mb_put_mbuf(mbp, m);
}
if (txdcount) {
if (error)
goto freerq;
mb_put_mbuf(mbp, m);
}
if (error)
goto freerq;
if (leftpcount || leftdcount) {
if (error)
goto bad;
/*
* this is an interim response, ignore it.
*/
}
while (leftpcount || leftdcount) {
if (error)
goto bad;
/*
* now we have known packet size as
* ALIGN4(len + 6 * 4 + 2)
* and need to decide which parts should go into request
*/
txdcount = 0;
doff = 0;
} else {
}
leftpcount -= txpcount;
leftdcount -= txdcount;
if (txpcount) {
if (error)
goto bad;
mb_put_mbuf(mbp, m);
}
if (txdcount) {
if (error)
goto bad;
mb_put_mbuf(mbp, m);
}
if (error)
goto bad;
} /* while left params or data */
goto bad;
}
}
bad:
}
return (error);
}
int
{
for (i = 0; ; ) {
/*
* Don't send any new requests if force unmount is underway.
* This check was moved into smb_rq_enqueue, called by
* smb_t2_request_int()
*/
if (!error)
break;
break;
if (++i > SMBMAXRESTARTS)
break;
} else {
}
}
return (error);
}
int
{
for (i = 0; ; ) {
/*
* Don't send any new requests if force unmount is underway.
* This check was moved into smb_rq_enqueue, called by
* smb_nt_request_int()
*/
if (!error)
break;
break;
if (++i > SMBMAXRESTARTS)
break;
} else {
}
}
return (error);
}