root/source4/libcli/raw/clitransport.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. smbcli_transport_event_handler
  2. transport_destructor
  3. smbcli_transport_error
  4. smbcli_transport_init
  5. smbcli_transport_dead
  6. smbcli_transport_connect_send
  7. map_session_refused_error
  8. smbcli_transport_connect_recv
  9. smbcli_transport_connect
  10. smbcli_transport_next_mid
  11. idle_handler
  12. smbcli_transport_idle_handler
  13. smbcli_transport_finish_recv
  14. smbcli_transport_process
  15. smbcli_timeout_handler
  16. smbcli_request_destructor
  17. smbcli_transport_send
  18. smb_raw_echo_send
  19. smb_raw_echo_recv
  20. smb_raw_echo

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    SMB client transport context management functions
   4 
   5    Copyright (C) Andrew Tridgell 1994-2005
   6    Copyright (C) James Myers 2003 <myersjj@samba.org>
   7    
   8    This program is free software; you can redistribute it and/or modify
   9    it under the terms of the GNU General Public License as published by
  10    the Free Software Foundation; either version 3 of the License, or
  11    (at your option) any later version.
  12    
  13    This program is distributed in the hope that it will be useful,
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16    GNU General Public License for more details.
  17    
  18    You should have received a copy of the GNU General Public License
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21 
  22 #include "includes.h"
  23 #include "libcli/raw/libcliraw.h"
  24 #include "libcli/raw/raw_proto.h"
  25 #include "lib/socket/socket.h"
  26 #include "../lib/util/dlinklist.h"
  27 #include "lib/events/events.h"
  28 #include "lib/stream/packet.h"
  29 #include "librpc/gen_ndr/ndr_nbt.h"
  30 #include "../libcli/nbt/libnbt.h"
  31 
  32 
  33 /*
  34   an event has happened on the socket
  35 */
  36 static void smbcli_transport_event_handler(struct tevent_context *ev, 
     /* [<][>][^][v][top][bottom][index][help] */
  37                                            struct tevent_fd *fde, 
  38                                            uint16_t flags, void *private_data)
  39 {
  40         struct smbcli_transport *transport = talloc_get_type(private_data,
  41                                                              struct smbcli_transport);
  42         if (flags & EVENT_FD_READ) {
  43                 packet_recv(transport->packet);
  44                 return;
  45         }
  46         if (flags & EVENT_FD_WRITE) {
  47                 packet_queue_run(transport->packet);
  48         }
  49 }
  50 
  51 /*
  52   destroy a transport
  53  */
  54 static int transport_destructor(struct smbcli_transport *transport)
     /* [<][>][^][v][top][bottom][index][help] */
  55 {
  56         smbcli_transport_dead(transport, NT_STATUS_LOCAL_DISCONNECT);
  57         return 0;
  58 }
  59 
  60 
  61 /*
  62   handle receive errors
  63 */
  64 static void smbcli_transport_error(void *private_data, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66         struct smbcli_transport *transport = talloc_get_type(private_data, struct smbcli_transport);
  67         smbcli_transport_dead(transport, status);
  68 }
  69 
  70 static NTSTATUS smbcli_transport_finish_recv(void *private_data, DATA_BLOB blob);
  71 
  72 /*
  73   create a transport structure based on an established socket
  74 */
  75 struct smbcli_transport *smbcli_transport_init(struct smbcli_socket *sock,
     /* [<][>][^][v][top][bottom][index][help] */
  76                                                TALLOC_CTX *parent_ctx, 
  77                                                bool primary, 
  78                                                struct smbcli_options *options,
  79                                                    struct smb_iconv_convenience *iconv_convenience)
  80 {
  81         struct smbcli_transport *transport;
  82 
  83         transport = talloc_zero(parent_ctx, struct smbcli_transport);
  84         if (!transport) return NULL;
  85 
  86         if (primary) {
  87                 transport->socket = talloc_steal(transport, sock);
  88         } else {
  89                 transport->socket = talloc_reference(transport, sock);
  90         }
  91         transport->negotiate.protocol = PROTOCOL_NT1;
  92         transport->options = *options;
  93         transport->negotiate.max_xmit = transport->options.max_xmit;
  94         transport->iconv_convenience = iconv_convenience;
  95 
  96         /* setup the stream -> packet parser */
  97         transport->packet = packet_init(transport);
  98         if (transport->packet == NULL) {
  99                 talloc_free(transport);
 100                 return NULL;
 101         }
 102         packet_set_private(transport->packet, transport);
 103         packet_set_socket(transport->packet, transport->socket->sock);
 104         packet_set_callback(transport->packet, smbcli_transport_finish_recv);
 105         packet_set_full_request(transport->packet, packet_full_request_nbt);
 106         packet_set_error_handler(transport->packet, smbcli_transport_error);
 107         packet_set_event_context(transport->packet, transport->socket->event.ctx);
 108         packet_set_nofree(transport->packet);
 109 
 110         smbcli_init_signing(transport);
 111 
 112         ZERO_STRUCT(transport->called);
 113 
 114         /* take over event handling from the socket layer - it only
 115            handles events up until we are connected */
 116         talloc_free(transport->socket->event.fde);
 117         transport->socket->event.fde = event_add_fd(transport->socket->event.ctx,
 118                                                     transport->socket->sock,
 119                                                     socket_get_fd(transport->socket->sock),
 120                                                     EVENT_FD_READ,
 121                                                     smbcli_transport_event_handler,
 122                                                     transport);
 123 
 124         packet_set_fde(transport->packet, transport->socket->event.fde);
 125         packet_set_serialise(transport->packet);
 126         talloc_set_destructor(transport, transport_destructor);
 127 
 128         return transport;
 129 }
 130 
 131 /*
 132   mark the transport as dead
 133 */
 134 void smbcli_transport_dead(struct smbcli_transport *transport, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 135 {
 136         smbcli_sock_dead(transport->socket);
 137 
 138         if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
 139                 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 140         }
 141 
 142         /* kill only the first pending receive - this is so that if
 143          that async function frees the connection we don't die trying
 144          to use old memory. The caller has to cope with only one
 145          network error */
 146         if (transport->pending_recv) {
 147                 struct smbcli_request *req = transport->pending_recv;
 148                 req->state = SMBCLI_REQUEST_ERROR;
 149                 req->status = status;
 150                 DLIST_REMOVE(transport->pending_recv, req);
 151                 if (req->async.fn) {
 152                         req->async.fn(req);
 153                 }
 154         }
 155 }
 156 
 157 
 158 /*
 159   send a session request
 160 */
 161 struct smbcli_request *smbcli_transport_connect_send(struct smbcli_transport *transport,
     /* [<][>][^][v][top][bottom][index][help] */
 162                                                      struct nbt_name *calling, 
 163                                                      struct nbt_name *called)
 164 {
 165         uint8_t *p;
 166         struct smbcli_request *req;
 167         DATA_BLOB calling_blob, called_blob;
 168         TALLOC_CTX *tmp_ctx = talloc_new(transport);
 169         NTSTATUS status;
 170 
 171         status = nbt_name_dup(transport, called, &transport->called);
 172         if (!NT_STATUS_IS_OK(status)) goto failed;
 173         
 174         status = nbt_name_to_blob(tmp_ctx, transport->iconv_convenience, &calling_blob, calling);
 175         if (!NT_STATUS_IS_OK(status)) goto failed;
 176 
 177         status = nbt_name_to_blob(tmp_ctx, transport->iconv_convenience, &called_blob, called);
 178         if (!NT_STATUS_IS_OK(status)) goto failed;
 179 
 180         /* allocate output buffer */
 181         req = smbcli_request_setup_nonsmb(transport, 
 182                                           NBT_HDR_SIZE + 
 183                                           calling_blob.length + called_blob.length);
 184         if (req == NULL) goto failed;
 185 
 186         /* put in the destination name */
 187         p = req->out.buffer + NBT_HDR_SIZE;
 188         memcpy(p, called_blob.data, called_blob.length);
 189         p += called_blob.length;
 190 
 191         memcpy(p, calling_blob.data, calling_blob.length);
 192         p += calling_blob.length;
 193 
 194         _smb_setlen(req->out.buffer, PTR_DIFF(p, req->out.buffer) - NBT_HDR_SIZE);
 195         SCVAL(req->out.buffer,0,0x81);
 196 
 197         if (!smbcli_request_send(req)) {
 198                 smbcli_request_destroy(req);
 199                 goto failed;
 200         }
 201 
 202         talloc_free(tmp_ctx);
 203         return req;
 204 
 205 failed:
 206         talloc_free(tmp_ctx);
 207         return NULL;
 208 }
 209 
 210 /*
 211   map a session request error to a NTSTATUS
 212  */
 213 static NTSTATUS map_session_refused_error(uint8_t error)
     /* [<][>][^][v][top][bottom][index][help] */
 214 {
 215         switch (error) {
 216         case 0x80:
 217         case 0x81:
 218                 return NT_STATUS_REMOTE_NOT_LISTENING;
 219         case 0x82:
 220                 return NT_STATUS_RESOURCE_NAME_NOT_FOUND;
 221         case 0x83:
 222                 return NT_STATUS_REMOTE_RESOURCES;
 223         }
 224         return NT_STATUS_UNEXPECTED_IO_ERROR;
 225 }
 226 
 227 
 228 /*
 229   finish a smbcli_transport_connect()
 230 */
 231 NTSTATUS smbcli_transport_connect_recv(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 232 {
 233         NTSTATUS status;
 234 
 235         if (!smbcli_request_receive(req)) {
 236                 smbcli_request_destroy(req);
 237                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
 238         }
 239 
 240         switch (CVAL(req->in.buffer,0)) {
 241         case 0x82:
 242                 status = NT_STATUS_OK;
 243                 break;
 244         case 0x83:
 245                 status = map_session_refused_error(CVAL(req->in.buffer,4));
 246                 break;
 247         case 0x84:
 248                 DEBUG(1,("Warning: session retarget not supported\n"));
 249                 status = NT_STATUS_NOT_SUPPORTED;
 250                 break;
 251         default:
 252                 status = NT_STATUS_UNEXPECTED_IO_ERROR;
 253                 break;
 254         }
 255 
 256         smbcli_request_destroy(req);
 257         return status;
 258 }
 259 
 260 
 261 /*
 262   send a session request (if needed)
 263 */
 264 bool smbcli_transport_connect(struct smbcli_transport *transport,
     /* [<][>][^][v][top][bottom][index][help] */
 265                               struct nbt_name *calling, 
 266                               struct nbt_name *called)
 267 {
 268         struct smbcli_request *req;
 269         NTSTATUS status;
 270 
 271         if (transport->socket->port == 445) {
 272                 return true;
 273         }
 274 
 275         req = smbcli_transport_connect_send(transport, 
 276                                             calling, called);
 277         status = smbcli_transport_connect_recv(req);
 278         return NT_STATUS_IS_OK(status);
 279 }
 280 
 281 /****************************************************************************
 282 get next mid in sequence
 283 ****************************************************************************/
 284 uint16_t smbcli_transport_next_mid(struct smbcli_transport *transport)
     /* [<][>][^][v][top][bottom][index][help] */
 285 {
 286         uint16_t mid;
 287         struct smbcli_request *req;
 288 
 289         mid = transport->next_mid;
 290 
 291 again:
 292         /* now check to see if this mid is being used by one of the 
 293            pending requests. This is quite efficient because the list is
 294            usually very short */
 295 
 296         /* the zero mid is reserved for requests that don't have a mid */
 297         if (mid == 0) mid = 1;
 298 
 299         for (req=transport->pending_recv; req; req=req->next) {
 300                 if (req->mid == mid) {
 301                         mid++;
 302                         goto again;
 303                 }
 304         }
 305 
 306         transport->next_mid = mid+1;
 307         return mid;
 308 }
 309 
 310 static void idle_handler(struct tevent_context *ev, 
     /* [<][>][^][v][top][bottom][index][help] */
 311                          struct tevent_timer *te, struct timeval t, void *private_data)
 312 {
 313         struct smbcli_transport *transport = talloc_get_type(private_data,
 314                                                              struct smbcli_transport);
 315         struct timeval next = timeval_add(&t, 0, transport->idle.period);
 316         transport->socket->event.te = event_add_timed(transport->socket->event.ctx, 
 317                                                       transport,
 318                                                       next,
 319                                                       idle_handler, transport);
 320         transport->idle.func(transport, transport->idle.private_data);
 321 }
 322 
 323 /*
 324   setup the idle handler for a transport
 325   the period is in microseconds
 326 */
 327 _PUBLIC_ void smbcli_transport_idle_handler(struct smbcli_transport *transport, 
     /* [<][>][^][v][top][bottom][index][help] */
 328                                    void (*idle_func)(struct smbcli_transport *, void *),
 329                                    uint64_t period,
 330                                    void *private_data)
 331 {
 332         transport->idle.func = idle_func;
 333         transport->idle.private_data = private_data;
 334         transport->idle.period = period;
 335 
 336         if (transport->socket->event.te != NULL) {
 337                 talloc_free(transport->socket->event.te);
 338         }
 339 
 340         transport->socket->event.te = event_add_timed(transport->socket->event.ctx, 
 341                                                       transport,
 342                                                       timeval_current_ofs(0, period),
 343                                                       idle_handler, transport);
 344 }
 345 
 346 /*
 347   we have a full request in our receive buffer - match it to a pending request
 348   and process
 349  */
 350 static NTSTATUS smbcli_transport_finish_recv(void *private_data, DATA_BLOB blob)
     /* [<][>][^][v][top][bottom][index][help] */
 351 {
 352         struct smbcli_transport *transport = talloc_get_type(private_data,
 353                                                              struct smbcli_transport);
 354         uint8_t *buffer, *hdr, *vwv;
 355         int len;
 356         uint16_t wct=0, mid = 0, op = 0;
 357         struct smbcli_request *req = NULL;
 358 
 359         buffer = blob.data;
 360         len = blob.length;
 361 
 362         hdr = buffer+NBT_HDR_SIZE;
 363         vwv = hdr + HDR_VWV;
 364 
 365         /* see if it could be an oplock break request */
 366         if (smbcli_handle_oplock_break(transport, len, hdr, vwv)) {
 367                 talloc_free(buffer);
 368                 return NT_STATUS_OK;
 369         }
 370 
 371         /* at this point we need to check for a readbraw reply, as
 372            these can be any length */
 373         if (transport->readbraw_pending) {
 374                 transport->readbraw_pending = 0;
 375 
 376                 /* it must match the first entry in the pending queue
 377                    as the client is not allowed to have outstanding
 378                    readbraw requests */
 379                 req = transport->pending_recv;
 380                 if (!req) goto error;
 381 
 382                 req->in.buffer = buffer;
 383                 talloc_steal(req, buffer);
 384                 req->in.size = len;
 385                 req->in.allocated = req->in.size;
 386                 goto async;
 387         }
 388 
 389         if (len >= MIN_SMB_SIZE) {
 390                 /* extract the mid for matching to pending requests */
 391                 mid = SVAL(hdr, HDR_MID);
 392                 wct = CVAL(hdr, HDR_WCT);
 393                 op  = CVAL(hdr, HDR_COM);
 394         }
 395 
 396         /* match the incoming request against the list of pending requests */
 397         for (req=transport->pending_recv; req; req=req->next) {
 398                 if (req->mid == mid) break;
 399         }
 400 
 401         /* see if it's a ntcancel reply for the current MID */
 402         req = smbcli_handle_ntcancel_reply(req, len, hdr);
 403 
 404         if (!req) {
 405                 DEBUG(1,("Discarding unmatched reply with mid %d op %d\n", mid, op));
 406                 goto error;
 407         }
 408 
 409         /* fill in the 'in' portion of the matching request */
 410         req->in.buffer = buffer;
 411         talloc_steal(req, buffer);
 412         req->in.size = len;
 413         req->in.allocated = req->in.size;
 414 
 415         /* handle NBT session replies */
 416         if (req->in.size >= 4 && req->in.buffer[0] != 0) {
 417                 req->status = NT_STATUS_OK;
 418                 goto async;
 419         }
 420 
 421         /* handle non-SMB replies */
 422         if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
 423                 req->state = SMBCLI_REQUEST_ERROR;
 424                 goto error;
 425         }
 426 
 427         if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
 428                 DEBUG(2,("bad reply size for mid %d\n", mid));
 429                 req->status = NT_STATUS_UNSUCCESSFUL;
 430                 req->state = SMBCLI_REQUEST_ERROR;
 431                 goto error;
 432         }
 433 
 434         req->in.hdr = hdr;
 435         req->in.vwv = vwv;
 436         req->in.wct = wct;
 437         if (req->in.size >= NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
 438                 req->in.data = req->in.vwv + VWV(wct) + 2;
 439                 req->in.data_size = SVAL(req->in.vwv, VWV(wct));
 440                 if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + req->in.data_size) {
 441                         DEBUG(3,("bad data size for mid %d\n", mid));
 442                         /* blergh - w2k3 gives a bogus data size values in some
 443                            openX replies */
 444                         req->in.data_size = req->in.size - (NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct));
 445                 }
 446         }
 447         req->in.ptr = req->in.data;
 448         req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
 449 
 450         smb_setup_bufinfo(req);
 451 
 452         if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
 453                 int eclass = CVAL(req->in.hdr,HDR_RCLS);
 454                 int code = SVAL(req->in.hdr,HDR_ERR);
 455                 if (eclass == 0 && code == 0) {
 456                         transport->error.e.nt_status = NT_STATUS_OK;
 457                 } else {
 458                         transport->error.e.nt_status = NT_STATUS_DOS(eclass, code);
 459                 }
 460         } else {
 461                 transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
 462         }
 463 
 464         req->status = transport->error.e.nt_status;
 465         if (NT_STATUS_IS_OK(req->status)) {
 466                 transport->error.etype = ETYPE_NONE;
 467         } else {
 468                 transport->error.etype = ETYPE_SMB;
 469         }
 470 
 471         if (!smbcli_request_check_sign_mac(req)) {
 472                 transport->error.etype = ETYPE_SOCKET;
 473                 transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
 474                 req->state = SMBCLI_REQUEST_ERROR;
 475                 req->status = NT_STATUS_ACCESS_DENIED;
 476                 goto error;
 477         };
 478 
 479 async:
 480         /* if this request has an async handler then call that to
 481            notify that the reply has been received. This might destroy
 482            the request so it must happen last */
 483 
 484         req->state = SMBCLI_REQUEST_DONE;
 485 
 486         if (req->recv_helper.fn) {
 487                 /*
 488                  * let the recv helper decide in
 489                  * what state the request really is
 490                  */
 491                 req->state = req->recv_helper.fn(req);
 492 
 493                 /* if more parts are needed, wait for them */
 494                 if (req->state <= SMBCLI_REQUEST_RECV) {
 495                         return NT_STATUS_OK;
 496                 }
 497         }
 498         DLIST_REMOVE(transport->pending_recv, req);
 499         if (req->async.fn) {
 500                 req->async.fn(req);
 501         }
 502         return NT_STATUS_OK;
 503 
 504 error:
 505         if (req) {
 506                 DLIST_REMOVE(transport->pending_recv, req);
 507                 req->state = SMBCLI_REQUEST_ERROR;
 508                 if (req->async.fn) {
 509                         req->async.fn(req);
 510                 }
 511         } else {
 512                 talloc_free(buffer);
 513         }
 514         return NT_STATUS_OK;
 515 }
 516 
 517 /*
 518   process some read/write requests that are pending
 519   return false if the socket is dead
 520 */
 521 _PUBLIC_ bool smbcli_transport_process(struct smbcli_transport *transport)
     /* [<][>][^][v][top][bottom][index][help] */
 522 {
 523         NTSTATUS status;
 524         size_t npending;
 525 
 526         packet_queue_run(transport->packet);
 527         if (transport->socket->sock == NULL) {
 528                 return false;
 529         }
 530 
 531         status = socket_pending(transport->socket->sock, &npending);
 532         if (NT_STATUS_IS_OK(status) && npending > 0) {
 533                 packet_recv(transport->packet);
 534         }
 535         if (transport->socket->sock == NULL) {
 536                 return false;
 537         }
 538         return true;
 539 }
 540 
 541 /*
 542   handle timeouts of individual smb requests
 543 */
 544 static void smbcli_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
     /* [<][>][^][v][top][bottom][index][help] */
 545                                    struct timeval t, void *private_data)
 546 {
 547         struct smbcli_request *req = talloc_get_type(private_data, struct smbcli_request);
 548 
 549         if (req->state == SMBCLI_REQUEST_RECV) {
 550                 DLIST_REMOVE(req->transport->pending_recv, req);
 551         }
 552         req->status = NT_STATUS_IO_TIMEOUT;
 553         req->state = SMBCLI_REQUEST_ERROR;
 554         if (req->async.fn) {
 555                 req->async.fn(req);
 556         }
 557 }
 558 
 559 
 560 /*
 561   destroy a request
 562 */
 563 static int smbcli_request_destructor(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 564 {
 565         if (req->state == SMBCLI_REQUEST_RECV) {
 566                 DLIST_REMOVE(req->transport->pending_recv, req);
 567         }
 568         return 0;
 569 }
 570 
 571 
 572 /*
 573   put a request into the send queue
 574 */
 575 void smbcli_transport_send(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 576 {
 577         DATA_BLOB blob;
 578         NTSTATUS status;
 579 
 580         /* check if the transport is dead */
 581         if (req->transport->socket->sock == NULL) {
 582                 req->state = SMBCLI_REQUEST_ERROR;
 583                 req->status = NT_STATUS_NET_WRITE_FAULT;
 584                 return;
 585         }
 586 
 587         blob = data_blob_const(req->out.buffer, req->out.size);
 588         status = packet_send(req->transport->packet, blob);
 589         if (!NT_STATUS_IS_OK(status)) {
 590                 req->state = SMBCLI_REQUEST_ERROR;
 591                 req->status = status;
 592                 return;
 593         }
 594 
 595         if (req->one_way_request) {
 596                 req->state = SMBCLI_REQUEST_DONE;
 597                 smbcli_request_destroy(req);
 598                 return;
 599         }
 600 
 601         req->state = SMBCLI_REQUEST_RECV;
 602         DLIST_ADD(req->transport->pending_recv, req);
 603 
 604         /* add a timeout */
 605         if (req->transport->options.request_timeout) {
 606                 event_add_timed(req->transport->socket->event.ctx, req, 
 607                                 timeval_current_ofs(req->transport->options.request_timeout, 0), 
 608                                 smbcli_timeout_handler, req);
 609         }
 610 
 611         talloc_set_destructor(req, smbcli_request_destructor);
 612 }
 613 
 614 
 615 /****************************************************************************
 616  Send an SMBecho (async send)
 617 *****************************************************************************/
 618 _PUBLIC_ struct smbcli_request *smb_raw_echo_send(struct smbcli_transport *transport,
     /* [<][>][^][v][top][bottom][index][help] */
 619                                          struct smb_echo *p)
 620 {
 621         struct smbcli_request *req;
 622 
 623         req = smbcli_request_setup_transport(transport, SMBecho, 1, p->in.size);
 624         if (!req) return NULL;
 625 
 626         SSVAL(req->out.vwv, VWV(0), p->in.repeat_count);
 627 
 628         memcpy(req->out.data, p->in.data, p->in.size);
 629 
 630         ZERO_STRUCT(p->out);
 631 
 632         if (!smbcli_request_send(req)) {
 633                 smbcli_request_destroy(req);
 634                 return NULL;
 635         }
 636 
 637         return req;
 638 }
 639 
 640 /****************************************************************************
 641  raw echo interface (async recv)
 642 ****************************************************************************/
 643 NTSTATUS smb_raw_echo_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 644                            struct smb_echo *p)
 645 {
 646         if (!smbcli_request_receive(req) ||
 647             smbcli_request_is_error(req)) {
 648                 goto failed;
 649         }
 650 
 651         SMBCLI_CHECK_WCT(req, 1);
 652         p->out.count++;
 653         p->out.sequence_number = SVAL(req->in.vwv, VWV(0));
 654         p->out.size = req->in.data_size;
 655         talloc_free(p->out.data);
 656         p->out.data = talloc_array(mem_ctx, uint8_t, p->out.size);
 657         NT_STATUS_HAVE_NO_MEMORY(p->out.data);
 658 
 659         if (!smbcli_raw_pull_data(&req->in.bufinfo, req->in.data, p->out.size, p->out.data)) {
 660                 req->status = NT_STATUS_BUFFER_TOO_SMALL;
 661         }
 662 
 663         if (p->out.count == p->in.repeat_count) {
 664                 return smbcli_request_destroy(req);
 665         }
 666 
 667         return NT_STATUS_OK;
 668 
 669 failed:
 670         return smbcli_request_destroy(req);
 671 }
 672 
 673 /****************************************************************************
 674  Send a echo (sync interface)
 675 *****************************************************************************/
 676 NTSTATUS smb_raw_echo(struct smbcli_transport *transport, struct smb_echo *p)
     /* [<][>][^][v][top][bottom][index][help] */
 677 {
 678         struct smbcli_request *req = smb_raw_echo_send(transport, p);
 679         return smbcli_request_simple_recv(req);
 680 }

/* [<][>][^][v][top][bottom][index][help] */