/*
                                  NETWOX
                             Network toolbox
                Copyright(c) 1999-2005 Laurent Constantin
                                  -----

  Main server    : http://www.laurentconstantin.com/
  Backup servers : http://go.to/laurentconstantin/
                   http://laurentconstantin.est-la.com/
                   http://laurentconstantin.free.fr/
                   http://membres.lycos.fr/lauconstantin/
  [my current email address is on the web servers]

                                  -----
  This file is part of Netwox.

  Netwox is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  version 2 as published by the Free Software Foundation.

  Netwox is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  General Public License for more details (http://www.gnu.org/).

------------------------------------------------------------------------
*/

/*-------------------------------------------------------------*/
#include "../netwox.h"

/*-------------------------------------------------------------*/
#define NETWOX_SMB_TEST_SNIFFEDPKT 0
#define NETWOX_SMB_TEST_SNIFFEDPKTNUM 1
#define NETWOX_SMB_TEST_SMBNBTSS 0
#define NETWOX_SMB_TEST_FLOW 0
#define NETWOX_SMB_TEST_SMBSIZE 0
#define NETWOX_SMB_TEST_SMBMSG 1
#define NETWOX_SMB_TEST_SMBCMD 1
#define NETWOX_SMB_TEST_SMBCMDTSC 1
#define NETWOX_SMB_TEST_SMBINIT 1

/*-------------------------------------------------------------*/
static netwib_err netwox_priv_smb_test_flow(netwib_bufpool *pbufpool,
                                            netwib_constbuf *ppkt,
                                            netwib_buf *psmb,
                                            netwib_port *plastport)
{
  netwib_linkhdr linkheader;
  netwib_iphdr ipheader;
  netwib_tcphdr tcpheader;
  netwib_buf tcpdata;
  netwib_err ret;

#if NETWOX_SMB_TEST_SNIFFEDPKT == 1
  netwib_er(netwox_pkt_link_display(pbufpool, NETWIB_DEVICE_DLTTYPE_ETHER,
                                    ppkt, NULL, NETWIB_ENCODETYPE_ARRAY,
                                    NETWIB_ENCODETYPE_DUMP));
#endif

  ret = netwib_pkt_decode_linkiptcpdata(NETWIB_DEVICE_DLTTYPE_ETHER, ppkt,
                                        &linkheader, &ipheader,
                                        &tcpheader, &tcpdata);
  if (ret != NETWIB_ERR_OK) {
    /* a non TCP packet was sniffed */
    return(NETWIB_ERR_OK);
  }
  if (tcpheader.seqnum == 0xA95AB74Au || tcpheader.seqnum == 0x8C342E9Eu ||
      tcpheader.seqnum == 0x909C535Eu) {
    /* bad packets */
    return(NETWIB_ERR_OK);
  }

  if (tcpheader.src == NETWOX_SERVICES_SMBNBTSS ||
      tcpheader.dst == NETWOX_SERVICES_SMBNBTSS) {
    if (*plastport == NETWOX_SERVICES_SMBNAKED) {
      if (netwib__buf_ref_data_size(psmb)) {
        netwib_er(netwib_fmt_display("Data from other port is present (%{uint32}).\n", netwib__buf_ref_data_size(psmb)));
        return(NETWOX_ERR_INTERNALERROR);
      }
    }
    *plastport = NETWOX_SERVICES_SMBNBTSS;
  } else if (tcpheader.src == NETWOX_SERVICES_SMBNAKED ||
             tcpheader.dst == NETWOX_SERVICES_SMBNAKED) {
    if (*plastport == NETWOX_SERVICES_SMBNBTSS) {
      if (netwib__buf_ref_data_size(psmb)) {
        netwib_er(netwib_fmt_display("Data from other port is present (%{uint32}).\n", netwib__buf_ref_data_size(psmb)));
        return(NETWOX_ERR_INTERNALERROR);
      }
    }
    *plastport = NETWOX_SERVICES_SMBNAKED;
  } else {
    /* not SMB */
    return(NETWIB_ERR_OK);
  }
  netwib_er(netwib_buf_append_buf(&tcpdata, psmb));
  return(NETWIB_ERR_OK);
  pbufpool = pbufpool;
}

/*-------------------------------------------------------------*/
#if NETWOX_SMB_TEST_SMBCMDTSC == 1
netwib_bool cmdisunicode;
netwox_smbcmdtscrfmt smbcmdtscrfmt;
netwib_bool smbcmdtscqlasterror;
static netwib_err netwox_priv_smb_test_smbcmdtscq(netwox_constsmbcmd *psmbcmd)
{
  netwox_smbcmdtscq smbcmdtscq;
  netwox_smbcmd smbcmd;
  netwib_buf buf1, buf2;
  netwib_cmp cmp;
  netwib_err ret=NETWIB_ERR_OK;

  netwib_er(netwox_smbcmdtscq_init(&smbcmdtscq));
  ret = netwox_smbcmdtscq_encode_smbcmd(psmbcmd, &smbcmdtscq);
  if (ret == NETWOX_ERR_NOTIMPLEMENTED) {
    smbcmdtscqlasterror = NETWIB_TRUE;
    return(NETWIB_ERR_OK);
  } else if (ret != NETWIB_ERR_OK) {
    return(ret);
  }
  smbcmdtscqlasterror = NETWIB_FALSE;

  netwib_er(netwib_buf_init_mallocdefault(&buf1));

  netwib_er(netwox_smbcmdtscq_show(&smbcmdtscq, &buf1));
  netwib_er(netwib_buf_display(&buf1, NETWIB_ENCODETYPE_DATA));

  netwib_er(netwox_smbcmdtscrfmt_init_smbcmdtscq(&smbcmdtscq,
                                                 &smbcmdtscrfmt));

  netwib_er(netwox_smbcmd_init(&smbcmd));
  netwib_er(netwox_smbcmd_selecttype(&smbcmd,
                                     NETWOX_SMBCMD_TYPE_TRANSACTION_Q));
  netwib_er(netwox_smbcmd_setdefault(&smbcmd));
  smbcmd.value.transaction_q.isunicode = psmbcmd->value.transaction_q.isunicode;
  netwib_er(netwox_smbcmdtscq_decode_smbcmd(&smbcmdtscq, &smbcmd));
  netwib_er(netwox_smbcmdtscq_close(&smbcmdtscq));

  netwib_er(netwox_smbcmdtscq_init(&smbcmdtscq));
  netwib_er(netwox_smbcmdtscq_encode_smbcmd(&smbcmd, &smbcmdtscq));
  netwib_er(netwib_buf_init_mallocdefault(&buf2));
  netwib_er(netwox_smbcmdtscq_show(&smbcmdtscq, &buf2));
  netwib_er(netwox_smbcmdtscq_close(&smbcmdtscq));
  netwib_er(netwox_smbcmd_close(&smbcmd));
  netwib_er(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
  netwib_er(netwib_buf_cmp(&buf1, &buf2, &cmp));
  if (cmp != NETWIB_CMP_EQ) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwib_buf_close(&buf2));
  netwib_er(netwib_buf_close(&buf1));

  return(NETWIB_ERR_OK);
}
static netwib_err netwox_priv_smb_test_smbcmdtscr(netwox_constsmbcmd *psmbcmd)
{
  netwox_smbcmdtscrstorage storage;
  netwox_smbcmdtscr smbcmdtscr;
  netwib_buf buf1, buf2;
  netwib_bool needmoremsg;
  netwib_cmp cmp;

  if (smbcmdtscqlasterror) {
    return(NETWIB_ERR_OK);
  }

  netwib_er(netwib_buf_init_mallocdefault(&buf1));
  netwib_er(netwib_buf_init_mallocdefault(&buf2));

  netwib_er(netwox_smbcmdtscrstorage_init(cmdisunicode, &storage));
  netwib_er(netwox_smbcmdtscrstorage_append_smbcmd(psmbcmd, &storage,
                                                   &needmoremsg));
  if (needmoremsg) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwox_smbcmdtscr_init(&smbcmdtscr));
  netwib_er(netwox_smbcmdtscr_encode_storager(&storage, &smbcmdtscrfmt,
                                              &smbcmdtscr));
  netwib_er(netwox_smbcmdtscrstorage_close(&storage));

  netwib_er(netwox_smbcmdtscr_show(&smbcmdtscr, &buf1));
  netwib_er(netwib_buf_display(&buf1, NETWIB_ENCODETYPE_DATA));

  netwib_er(netwox_smbcmdtscrstorage_init(cmdisunicode, &storage));
  netwib_er(netwox_smbcmdtscr_decode_storager(&smbcmdtscr, &smbcmdtscrfmt,
                                              &storage));
  netwib_er(netwox_smbcmdtscr_close(&smbcmdtscr));

  netwib_er(netwox_smbcmdtscr_init(&smbcmdtscr));
  netwib_er(netwox_smbcmdtscr_encode_storager(&storage, &smbcmdtscrfmt,
                                              &smbcmdtscr));

  netwib_er(netwox_smbcmdtscr_show(&smbcmdtscr, &buf2));
  netwib_er(netwox_smbcmdtscr_close(&smbcmdtscr));
  netwib_er(netwox_smbcmdtscrstorage_close(&storage));
  netwib_er(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
  netwib_er(netwib_buf_cmp(&buf1, &buf2, &cmp));
  if (cmp != NETWIB_CMP_EQ) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwib_buf_close(&buf2));
  netwib_er(netwib_buf_close(&buf1));

  return(NETWIB_ERR_OK);
}
netwox_smbcmdtsc2rfmt smbcmdtsc2rfmt;
netwib_bool smbcmdtsc2qlasterror;
static netwib_err netwox_priv_smb_test_smbcmdtsc2q(netwox_constsmbcmd *psmbcmd)
{
  netwox_smbcmdtsc2q smbcmdtsc2q;
  netwox_smbcmd smbcmd;
  netwib_buf buf1, buf2;
  netwib_cmp cmp;
  netwib_err ret=NETWIB_ERR_OK;

  netwib_er(netwox_smbcmdtsc2q_init(&smbcmdtsc2q));
  ret = netwox_smbcmdtsc2q_encode_smbcmd(psmbcmd, &smbcmdtsc2q);
  if (ret == NETWOX_ERR_NOTIMPLEMENTED) {
    smbcmdtsc2qlasterror = NETWIB_TRUE;
    return(NETWIB_ERR_OK);
  } else if (ret != NETWIB_ERR_OK) {
    return(ret);
  }
  smbcmdtsc2qlasterror = NETWIB_FALSE;

  netwib_er(netwib_buf_init_mallocdefault(&buf1));
  netwib_er(netwox_smbcmdtsc2q_show(&smbcmdtsc2q, &buf1));
  netwib_er(netwib_buf_display(&buf1, NETWIB_ENCODETYPE_DATA));

#if 0
  smbcmdtsc2qlasterror = NETWIB_TRUE;
  netwib_er(netwox_smbcmdtsc2q_close(&smbcmdtsc2q));
  netwib_er(netwib_buf_close(&buf1));
  return(NETWIB_ERR_OK);
#elif 0
  smbcmdtsc2qlasterror = NETWIB_TRUE;
#endif

  netwib_er(netwox_smbcmdtsc2rfmt_init_smbcmdtsc2q(&smbcmdtsc2q,
                                                   &smbcmdtsc2rfmt));

  netwib_er(netwox_smbcmd_init(&smbcmd));
  netwib_er(netwox_smbcmd_selecttype(&smbcmd,
                                     NETWOX_SMBCMD_TYPE_TRANSACTION2_Q));
  netwib_er(netwox_smbcmd_setdefault(&smbcmd));
  smbcmd.value.transaction2_q.isunicode = psmbcmd->value.transaction2_q.isunicode;
  netwib_er(netwox_smbcmdtsc2q_decode_smbcmd(&smbcmdtsc2q, &smbcmd));
  netwib_er(netwox_smbcmdtsc2q_close(&smbcmdtsc2q));

  netwib_er(netwox_smbcmdtsc2q_init(&smbcmdtsc2q));
  netwib_er(netwox_smbcmdtsc2q_encode_smbcmd(&smbcmd, &smbcmdtsc2q));
  netwib_er(netwib_buf_init_mallocdefault(&buf2));
  netwib_er(netwox_smbcmdtsc2q_show(&smbcmdtsc2q, &buf2));
  netwib_er(netwox_smbcmdtsc2q_close(&smbcmdtsc2q));
  netwib_er(netwox_smbcmd_close(&smbcmd));
  netwib_er(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
  netwib_er(netwib_buf_cmp(&buf1, &buf2, &cmp));
  if (cmp != NETWIB_CMP_EQ) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwib_buf_close(&buf2));
  netwib_er(netwib_buf_close(&buf1));

  return(NETWIB_ERR_OK);
}
static netwib_err netwox_priv_smb_test_smbcmdtsc2r(netwox_constsmbcmd *psmbcmd)
{
  netwox_smbcmdtsc2rstorage storage;
  netwox_smbcmdtsc2r smbcmdtsc2r;
  netwib_buf buf1, buf2;
  netwib_bool needmoremsg;
  netwib_cmp cmp;

  if (smbcmdtsc2qlasterror) {
    return(NETWIB_ERR_OK);
  }

  netwib_er(netwox_smbcmdtsc2rstorage_init(cmdisunicode, &storage));
  netwib_er(netwox_smbcmdtsc2rstorage_append_smbcmd(psmbcmd, &storage,
                                                    &needmoremsg));
  if (needmoremsg) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwox_smbcmdtsc2r_init(&smbcmdtsc2r));
  netwib_er(netwox_smbcmdtsc2r_encode_storager(&storage, &smbcmdtsc2rfmt,
                                               &smbcmdtsc2r));
  netwib_er(netwox_smbcmdtsc2rstorage_close(&storage));

  netwib_er(netwib_buf_init_mallocdefault(&buf1));
  netwib_er(netwox_smbcmdtsc2r_show(&smbcmdtsc2r, &buf1));
  netwib_er(netwib_buf_display(&buf1, NETWIB_ENCODETYPE_DATA));

#if 0
  netwib_er(netwox_smbcmdtsc2r_close(&smbcmdtsc2r));
  netwib_er(netwib_buf_close(&buf1));
  return(NETWIB_ERR_OK);
#endif

  netwib_er(netwox_smbcmdtsc2rstorage_init(cmdisunicode, &storage));
  netwib_er(netwox_smbcmdtsc2r_decode_storager(&smbcmdtsc2r, &smbcmdtsc2rfmt,
                                               &storage));
  netwib_er(netwox_smbcmdtsc2r_close(&smbcmdtsc2r));

  netwib_er(netwox_smbcmdtsc2r_init(&smbcmdtsc2r));
  netwib_er(netwox_smbcmdtsc2r_encode_storager(&storage, &smbcmdtsc2rfmt,
                                               &smbcmdtsc2r));

  netwib_er(netwib_buf_init_mallocdefault(&buf2));
  netwib_er(netwox_smbcmdtsc2r_show(&smbcmdtsc2r, &buf2));
  netwib_er(netwox_smbcmdtsc2r_close(&smbcmdtsc2r));
  netwib_er(netwox_smbcmdtsc2rstorage_close(&storage));
  netwib_er(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
  netwib_er(netwib_buf_cmp(&buf1, &buf2, &cmp));
  if (cmp != NETWIB_CMP_EQ) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwib_buf_close(&buf2));
  netwib_er(netwib_buf_close(&buf1));

  return(NETWIB_ERR_OK);
}
netwox_smbcmdtscntrfmt smbcmdtscntrfmt;
netwib_bool smbcmdtscntqlasterror;
static netwib_err netwox_priv_smb_test_smbcmdtscntq(netwox_constsmbcmd *psmbcmd)
{
  netwox_smbcmdtscntq smbcmdtscntq;
  netwox_smbcmd smbcmd;
  netwib_buf buf1, buf2;
  netwib_cmp cmp;
  netwib_err ret=NETWIB_ERR_OK;

  netwib_er(netwox_smbcmdtscntq_init(&smbcmdtscntq));
  ret = netwox_smbcmdtscntq_encode_smbcmd(psmbcmd, &smbcmdtscntq);
  if (ret == NETWOX_ERR_NOTIMPLEMENTED) {
    smbcmdtscntqlasterror = NETWIB_TRUE;
    return(NETWIB_ERR_OK);
  } else if (ret != NETWIB_ERR_OK) {
    return(ret);
  }
  smbcmdtscntqlasterror = NETWIB_FALSE;

  netwib_er(netwib_buf_init_mallocdefault(&buf1));
  netwib_er(netwox_smbcmdtscntq_show(&smbcmdtscntq, &buf1));
  netwib_er(netwib_buf_display(&buf1, NETWIB_ENCODETYPE_DATA));

#if 0
  smbcmdtsc2qlasterror = NETWIB_TRUE;
  netwib_er(netwox_smbcmdtsc2q_close(&smbcmdtsc2q));
  netwib_er(netwib_buf_close(&buf1));
  return(NETWIB_ERR_OK);
#elif 0
  smbcmdtsc2qlasterror = NETWIB_TRUE;
#endif

  netwib_er(netwox_smbcmdtscntrfmt_init_smbcmdtscntq(&smbcmdtscntq,
                                                     &smbcmdtscntrfmt));

  netwib_er(netwox_smbcmd_init(&smbcmd));
  netwib_er(netwox_smbcmd_selecttype(&smbcmd,
                                     NETWOX_SMBCMD_TYPE_NTTRANSACT_Q));
  netwib_er(netwox_smbcmd_setdefault(&smbcmd));
  smbcmd.value.nttransact_q.isunicode = psmbcmd->value.nttransact_q.isunicode;
  netwib_er(netwox_smbcmdtscntq_decode_smbcmd(&smbcmdtscntq, &smbcmd));
  netwib_er(netwox_smbcmdtscntq_close(&smbcmdtscntq));

  netwib_er(netwox_smbcmdtscntq_init(&smbcmdtscntq));
  netwib_er(netwox_smbcmdtscntq_encode_smbcmd(&smbcmd, &smbcmdtscntq));
  netwib_er(netwib_buf_init_mallocdefault(&buf2));
  netwib_er(netwox_smbcmdtscntq_show(&smbcmdtscntq, &buf2));
  netwib_er(netwox_smbcmdtscntq_close(&smbcmdtscntq));
  netwib_er(netwox_smbcmd_close(&smbcmd));
  netwib_er(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
  netwib_er(netwib_buf_cmp(&buf1, &buf2, &cmp));
  if (cmp != NETWIB_CMP_EQ) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwib_buf_close(&buf2));
  netwib_er(netwib_buf_close(&buf1));

  return(NETWIB_ERR_OK);
}
static netwib_err netwox_priv_smb_test_smbcmdtscntr(netwox_constsmbcmd *psmbcmd)
{
  netwox_smbcmdtscntrstorage storage;
  netwox_smbcmdtscntr smbcmdtscntr;
  netwib_buf buf1, buf2;
  netwib_bool needmoremsg;
  netwib_cmp cmp;

  if (smbcmdtscntqlasterror) {
    return(NETWIB_ERR_OK);
  }

  netwib_er(netwox_smbcmdtscntrstorage_init(cmdisunicode, &storage));
  netwib_er(netwox_smbcmdtscntrstorage_append_smbcmd(psmbcmd, &storage,
                                                     &needmoremsg));
  if (needmoremsg) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwox_smbcmdtscntr_init(&smbcmdtscntr));
  netwib_er(netwox_smbcmdtscntr_encode_storager(&storage, &smbcmdtscntrfmt,
                                                &smbcmdtscntr));
  netwib_er(netwox_smbcmdtscntrstorage_close(&storage));

  netwib_er(netwib_buf_init_mallocdefault(&buf1));
  netwib_er(netwox_smbcmdtscntr_show(&smbcmdtscntr, &buf1));
  netwib_er(netwib_buf_display(&buf1, NETWIB_ENCODETYPE_DATA));

  netwib_er(netwox_smbcmdtscntrstorage_init(cmdisunicode, &storage));
  netwib_er(netwox_smbcmdtscntr_decode_storager(&smbcmdtscntr,
                                                &smbcmdtscntrfmt,
                                                &storage));
  netwib_er(netwox_smbcmdtscntr_close(&smbcmdtscntr));

  netwib_er(netwox_smbcmdtscntr_init(&smbcmdtscntr));
  netwib_er(netwox_smbcmdtscntr_encode_storager(&storage, &smbcmdtscntrfmt,
                                                &smbcmdtscntr));

  netwib_er(netwib_buf_init_mallocdefault(&buf2));
  netwib_er(netwox_smbcmdtscntr_show(&smbcmdtscntr, &buf2));
  netwib_er(netwox_smbcmdtscntr_close(&smbcmdtscntr));
  netwib_er(netwox_smbcmdtscntrstorage_close(&storage));
  netwib_er(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
  netwib_er(netwib_buf_cmp(&buf1, &buf2, &cmp));
  if (cmp != NETWIB_CMP_EQ) {
    return(NETWOX_ERR_INTERNALERROR);
  }

  netwib_er(netwib_buf_close(&buf2));
  netwib_er(netwib_buf_close(&buf1));

  return(NETWIB_ERR_OK);
}
#endif

/*-------------------------------------------------------------*/
static netwib_err netwox_priv_smb_test_analyze(netwib_buf *psmb,
                                               netwib_port lastport)
{
  netwib_buf smbpkt, tmp, label, buf;
  netwib_uint32 skipsize;
  netwox_smbnbtss smbnbtss;
  netwox_smbnaked smbnaked;
  netwox_smbmsg smbmsg;
  netwib_err ret=NETWIB_ERR_OK;

  netwib_er(netwib_buf_init_ext_empty(&smbpkt));
  if (lastport == NETWOX_SERVICES_SMBNBTSS) {
    netwib_er(netwox_pkt_decode_smbnbtss(psmb, &smbnbtss, &skipsize));
    psmb->beginoffset += skipsize;
#if NETWOX_SMB_TEST_SMBNBTSS == 1
    netwib_er(netwib_fmt_display("type = %{uint32}\n", smbnbtss.smbnbtsstype));
#endif
    switch(smbnbtss.smbnbtsstype) {
    case NETWOX_SMBNBTSSTYPE_MSG :
      smbpkt = smbnbtss.payload.msg.smbpkt;
      break;
    case NETWOX_SMBNBTSSTYPE_REQUEST :
      netwib_er(netwib_buf_init_mallocdefault(&tmp));
#if NETWOX_SMB_TEST_SMBNBTSS == 1
      netwib_er(netwib_fmt_display("called  = %{byte} ",
                                   smbnbtss.payload.request.callednamelabel));
#endif
      netwib_er(netwib_buf_init_ext_arrayfilled(smbnbtss.payload.request.calledname, sizeof(smbnbtss.payload.request.calledname), &label));
      netwib_er(netwox_buf_append_netbiosname(&label, &tmp));
#if NETWOX_SMB_TEST_SMBNBTSS == 1
      netwib_er(netwib_buf_display(&tmp, NETWIB_ENCODETYPE_MIXED));
      netwib_er(netwib_fmt_display("\ncalling = %{byte} ",
                                   smbnbtss.payload.request.callingnamelabel));
#endif
      netwib_er(netwib_buf_init_ext_arrayfilled(smbnbtss.payload.request.callingname, sizeof(smbnbtss.payload.request.callingname), &label));
      netwib__buf_reinit(&tmp);
      netwib_er(netwox_buf_append_netbiosname(&label, &tmp));
#if NETWOX_SMB_TEST_SMBNBTSS == 1
      netwib_er(netwib_buf_display(&tmp, NETWIB_ENCODETYPE_MIXED));
      netwib_er(netwib_fmt_display("\n"));
#endif
      netwib_er(netwib_buf_close(&tmp));
      return(NETWIB_ERR_OK);
    case NETWOX_SMBNBTSSTYPE_RESPPOSITIVE :
      return(NETWIB_ERR_OK);
    case NETWOX_SMBNBTSSTYPE_RESPNEGATIVE :
#if NETWOX_SMB_TEST_SMBNBTSS == 1
      netwib_er(netwib_fmt_display("error = %{uint32}\n",
                                   smbnbtss.payload.respnegative.error));
#endif
      return(NETWIB_ERR_OK);
    case NETWOX_SMBNBTSSTYPE_RESPRETARGET :
#if NETWOX_SMB_TEST_SMBNBTSS == 1
      netwib_er(netwib_fmt_display("target = %{ip}:%{port}\n",
                                   smbnbtss.payload.respretarget.host,
                                   smbnbtss.payload.respretarget.port));
#endif
      return(NETWIB_ERR_OK);
    case NETWOX_SMBNBTSSTYPE_KEEPALIVE :
      return(NETWIB_ERR_OK);
    default :
      return(NETWOX_ERR_INTERNALERROR);
    }
  } else if (lastport == NETWOX_SERVICES_SMBNAKED) {
    netwib_er(netwox_pkt_decode_smbnaked(psmb, &smbnaked, &skipsize));
    psmb->beginoffset += skipsize;
    smbpkt = smbnaked.smbpkt;
  } else {
    return(NETWOX_ERR_INTERNALERROR);
  }

#if NETWOX_SMB_TEST_SMBSIZE == 1
  netwib_er(netwib_fmt_display("SMB pkt size = %{uint32}\n",
                               netwib__buf_ref_data_size(&smbpkt)));
#endif
  netwib_er(netwox_pkt_decode_smbmsg(&smbpkt, &smbmsg));
  netwib_eg(netwib_buf_init_mallocdefault(&buf));
  netwib_eg(netwox_smbmsg_show(&smbmsg, &buf));
  netwib_eg(netwib_buf_display(&buf, NETWIB_ENCODETYPE_DATA));
#if NETWOX_SMB_TEST_SMBMSG == 1 || NETWOX_SMB_TEST_SMBCMD == 1
  {
    netwib_buf buf2;
    netwox_smbmsg smbmsg2;
    netwib_cmp cmp;
    netwib_eg(netwib_buf_init_mallocdefault(&buf2));
#if NETWOX_SMB_TEST_SMBMSG == 1
    {
      netwib_buf pkt;
      netwib_er(netwib_fmt_display("smbmsg test\n"));
      netwib_eg(netwib_buf_init_mallocdefault(&pkt));
      netwib_eg(netwox_pkt_append_smbmsg(&smbmsg, &pkt));
      netwib_eg(netwib_buf_display(&pkt, NETWIB_ENCODETYPE_DUMP));
      netwib_eg(netwox_pkt_decode_smbmsg(&pkt, &smbmsg2));
      netwib_eg(netwox_smbmsg_show(&smbmsg2, &buf2));
      netwib_eg(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
      netwib_eg(netwib_buf_cmp(&buf, &buf2, &cmp));
      if (cmp != NETWIB_CMP_EQ) {
        return(NETWOX_ERR_INTERNALERROR);
      }
      netwib_eg(netwib_buf_close(&pkt));
    }
#endif
#if NETWOX_SMB_TEST_SMBCMD == 1
    {
      netwox_smbcmd smbcmd;
      netwib_uint32 i;
      netwib_bool symetric, noerror;
      netwib_eg(netwib_fmt_display("smbcmd test\n"));
      netwib_eg(netwox_smbmsg_init(&smbmsg2));
      smbmsg2.hdr = smbmsg.hdr;
      symetric = NETWIB_TRUE;
      noerror = NETWIB_TRUE;
      for (i = 0; i < smbmsg.numcmds; i++) {
        netwib_eg(netwib_fmt_display("i = %{uint32}\n", i));
        netwib_eg(netwox_smbcmd_init(&smbcmd));
        ret = netwox_smbmsg_decode_smbcmd(&smbmsg, i, &smbcmd);
        if (ret != NETWIB_ERR_OK) {
          if (smbmsg.hdr.error &&
              netwib__buf_ref_data_size(&smbmsg.cmds[i].para) == 0 &&
              netwib__buf_ref_data_size(&smbmsg.cmds[i].data) == 0) {
            netwib_eg(netwib_fmt_display(" ignore error\n"));
            noerror = NETWIB_FALSE;
            ret = NETWIB_ERR_OK;
          } else {
            netwib_goto(ret);
          }
        } else {
          if (smbcmd.type == NETWOX_SMBCMD_TYPE_NEGOTIATE_Q) {
            symetric = NETWIB_FALSE;
          }
          netwib__buf_reinit(&buf2);
          netwib_eg(netwox_smbcmd_show(&smbcmd, &buf2));
          netwib_eg(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
          smbmsg2.cmds[i].dataisaligned = smbmsg.cmds[i].dataisaligned;
          netwib_eg(netwox_smbmsg_append_smbcmd(&smbcmd, &smbmsg2));
        }
        netwib_eg(netwox_smbcmd_close(&smbcmd));
      }
      if (noerror) {
        netwib__buf_reinit(&buf2);
        netwib_eg(netwox_smbmsg_show(&smbmsg2, &buf2));
        netwib_eg(netwib_buf_display(&buf2, NETWIB_ENCODETYPE_DATA));
        if (symetric) {
          netwib_eg(netwib_buf_cmp(&buf, &buf2, &cmp));
          if (cmp != NETWIB_CMP_EQ) {
            return(NETWOX_ERR_INTERNALERROR);
          }
        }
      }
      netwib_eg(netwox_smbmsg_close(&smbmsg2));
    }
#endif
#if NETWOX_SMB_TEST_SMBCMDTSC == 1
    {
      netwox_smbcmd smbcmd;
      netwib_uint32 i;
      cmdisunicode = NETWIB_FALSE;
      if (smbmsg.hdr.flags2 & NETWOX_SMBMSG_FLAGS2_UNICODESTRINGS) {
        cmdisunicode = NETWIB_TRUE;
      }
      netwib_eg(netwib_fmt_display("smbcmdtsc test\n"));
      for (i = 0; i < smbmsg.numcmds; i++) {
        netwib_eg(netwib_fmt_display("i = %{uint32}\n", i));
        netwib_eg(netwox_smbcmd_init(&smbcmd));
        ret = netwox_smbmsg_decode_smbcmd(&smbmsg, i, &smbcmd);
        if (ret == NETWIB_ERR_OK) {
          if (smbcmd.type == NETWOX_SMBCMD_TYPE_TRANSACTION_Q) {
            netwib_eg(netwox_priv_smb_test_smbcmdtscq(&smbcmd));
          } else if (smbcmd.type == NETWOX_SMBCMD_TYPE_TRANSACTION_R) {
            netwib_eg(netwox_priv_smb_test_smbcmdtscr(&smbcmd));
          } else if (smbcmd.type == NETWOX_SMBCMD_TYPE_TRANSACTION2_Q) {
            netwib_eg(netwox_priv_smb_test_smbcmdtsc2q(&smbcmd));
          } else if (smbcmd.type == NETWOX_SMBCMD_TYPE_TRANSACTION2_R) {
            netwib_eg(netwox_priv_smb_test_smbcmdtsc2r(&smbcmd));
          } else if (smbcmd.type == NETWOX_SMBCMD_TYPE_NTTRANSACT_Q) {
            netwib_eg(netwox_priv_smb_test_smbcmdtscntq(&smbcmd));
          } else if (smbcmd.type == NETWOX_SMBCMD_TYPE_NTTRANSACT_R) {
            if (smbmsg.hdr.error) {
              netwib_eg(netwib_fmt_display("Ignore msg with error\n", ret));
            } else {
              netwib_eg(netwox_priv_smb_test_smbcmdtscntr(&smbcmd));
            }
          }
        } else {
          netwib_eg(netwib_fmt_display("error = %{uint32} (ignore)\n", ret));
          ret = NETWIB_ERR_OK;
        }
        netwib_eg(netwox_smbcmd_close(&smbcmd));
      }
    }
#endif
    netwib_eg(netwib_buf_close(&buf2));
  }
#endif
  netwib_eg(netwib_buf_close(&buf));

 netwib_gotolabel:
  if (ret == NETWIB_ERR_DATAMISSING) {
    ret = NETWIB_ERR_NOTCONVERTED;
  }
  return(ret);
}

/*-------------------------------------------------------------*/
netwib_err netwox_smb_test(void)
{
  netwib_buf pkt, smb, filename;
  netwib_bufpool *pbufpool;
  netwib_io *piorecord;
  netwib_port lastport;
  netwib_uint32 i;
  netwib_err ret=NETWIB_ERR_OK;

#if NETWOX_SMB_TEST_SMBINIT == 1
  {
    netwib_buf buf;
    netwox_smbmsg smbmsg;
    netwox_smbcmd smbcmd;
    netwib_er(netwib_buf_init_mallocdefault(&buf));
    netwib_er(netwox_smbmsg_init(&smbmsg));
    netwib_er(netwox_smbmsg_setdefault(&smbmsg));
    netwib_er(netwox_smbmsg_show(&smbmsg, &buf));
    netwib_er(netwox_smbmsg_close(&smbmsg));
    netwib_er(netwib_buf_display(&buf, NETWIB_ENCODETYPE_DATA));
    for (i = 1; i <= 60; i++) {
      netwib__buf_reinit(&buf);
      netwib_er(netwib_fmt_display("\n"));
      netwib_er(netwox_smbcmd_init(&smbcmd));
      ret = netwox_smbcmd_selecttype(&smbcmd, i);
      if (ret != NETWIB_ERR_OK) {
        netwib_er(netwib_fmt_display("i %{uint32} not yet implemented\n", i));
      } else {
        netwib_er(netwox_smbcmd_setdefault(&smbcmd));
        netwib_er(netwox_smbcmd_show(&smbcmd, &buf));
        netwib_er(netwib_buf_display(&buf, NETWIB_ENCODETYPE_DATA));
      }
      netwib_er(netwox_smbcmd_close(&smbcmd));
    }
    netwib_er(netwib_buf_close(&buf));
  }
#endif

  /* initialize record */
  netwib_er(netwib_buf_init_ext_text("file.pcap", &filename));
  netwib_er(netwib_io_init_record_read(&filename, &piorecord));

  /* main loop */
  netwib_er(netwib_buf_init_mallocdefault(&pkt));
  netwib_er(netwib_buf_init_mallocdefault(&smb));
  smb.flags |= NETWIB_BUF_FLAGS_CANSLIDE;
  lastport = NETWOX_SERVICES_SMBNBTSS;
  netwib_er(netwib_bufpool_initdefault(&pbufpool));
  i = 0;
  while (NETWIB_TRUE) {
    i++;
#if NETWOX_SMB_TEST_SNIFFEDPKTNUM == 1
    netwib_er(netwib_fmt_display("\ni=%{uint32}\n", i));
#endif
    /* read packet */
    netwib__buf_reinit(&pkt);
    ret = netwib_io_read(piorecord, &pkt);
    if (ret == NETWIB_ERR_DATANOTAVAIL) {
      continue;
    } else if (ret != NETWIB_ERR_OK) {
      if (ret == NETWIB_ERR_DATAEND) ret = NETWIB_ERR_OK;
      break;
    }
    if ((i >= 8803 && i <= 8806) ||
        (i >= 9102 && i <= 9116) ||
        (i >= 9378 && i <= 9381) ||
        (i >= 2694 && i <= 2696) ||
        (i >= 6889 && i <= 6890) ||
        (i >= 1558 && i <= 1559) ||
        (i >= 1590 && i <= 1591) ||
        (i >= 1976 && i <= 1977) ||
        (i >= 2008 && i <= 2009) ||
        (i >= 5773 && i <= 5774) ||
        (i == 1570) || (i == 3272) ) {
      /* sometimes, query and replies overlap : this algorithm is too
         simple to deal with them, so ignore */
      continue;
    }
#if 0
    if (i < 8) {
      continue;
    }
#endif
    /* add its data to flow (group both ways) */
    netwib_er(netwox_priv_smb_test_flow(pbufpool, &pkt, &smb, &lastport));
    /* analyze */
    ret = netwox_priv_smb_test_analyze(&smb, lastport);
    if (ret == NETWIB_ERR_DATAMISSING) {
#if NETWOX_SMB_TEST_FLOW == 1
      netwib_er(netwib_fmt_display("Data is missing.\n"));
#endif
      continue;
    }
    if (ret != NETWIB_ERR_OK) {
      break;
    }
  }

  /* close */
  netwib_er(netwib_bufpool_close(&pbufpool));
  netwib_er(netwib_buf_close(&smb));
  netwib_er(netwib_buf_close(&pkt));
  netwib_er(netwib_io_close(&piorecord));

  return(ret);
}

