2 * Copyright (c) 2000-2001, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/sys/netsmb/smb_rq.c,v 1.1.2.2 2002/04/23 03:45:01 bp Exp $
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
40 #include <sys/sysctl.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
51 MALLOC_DEFINE(M_SMBRQ
, "SMBRQ", "SMB request");
53 MODULE_DEPEND(netsmb
, libmchain
, 1, 1, 1);
55 static int smb_rq_reply(struct smb_rq
*rqp
);
56 static int smb_rq_enqueue(struct smb_rq
*rqp
);
57 static int smb_rq_getenv(struct smb_connobj
*layer
,
58 struct smb_vc
**vcpp
, struct smb_share
**sspp
);
59 static int smb_rq_new(struct smb_rq
*rqp
, u_char cmd
);
60 static int smb_t2_reply(struct smb_t2rq
*t2p
);
63 smb_rq_alloc(struct smb_connobj
*layer
, u_char cmd
, struct smb_cred
*scred
,
69 rqp
= kmalloc(sizeof(*rqp
), M_SMBRQ
, M_WAITOK
);
70 error
= smb_rq_init(rqp
, layer
, cmd
, scred
);
71 rqp
->sr_flags
|= SMBR_ALLOCED
;
80 static char tzero
[12];
83 smb_rq_init(struct smb_rq
*rqp
, struct smb_connobj
*layer
, u_char cmd
,
84 struct smb_cred
*scred
)
88 bzero(rqp
, sizeof(*rqp
));
89 smb_sl_init(&rqp
->sr_slock
, "srslock");
90 error
= smb_rq_getenv(layer
, &rqp
->sr_vc
, &rqp
->sr_share
);
93 error
= smb_vc_access(rqp
->sr_vc
, scred
, SMBM_EXEC
);
97 error
= smb_share_access(rqp
->sr_share
, scred
, SMBM_EXEC
);
101 rqp
->sr_cred
= scred
;
102 rqp
->sr_mid
= smb_vc_nextmid(rqp
->sr_vc
);
103 return smb_rq_new(rqp
, cmd
);
107 smb_rq_new(struct smb_rq
*rqp
, u_char cmd
)
109 struct smb_vc
*vcp
= rqp
->sr_vc
;
110 struct mbchain
*mbp
= &rqp
->sr_rq
;
116 md_done(&rqp
->sr_rp
);
117 error
= mb_init(mbp
);
120 mb_put_mem(mbp
, SMB_SIGNATURE
, SMB_SIGLEN
, MB_MSYSTEM
);
121 mb_put_uint8(mbp
, cmd
);
122 mb_put_uint32le(mbp
, 0); /* DosError */
123 mb_put_uint8(mbp
, vcp
->vc_hflags
);
124 flags2
= vcp
->vc_hflags2
;
125 if (cmd
== SMB_COM_TRANSACTION
|| cmd
== SMB_COM_TRANSACTION_SECONDARY
)
126 flags2
&= ~SMB_FLAGS2_UNICODE
;
127 if (cmd
== SMB_COM_NEGOTIATE
)
128 flags2
&= ~SMB_FLAGS2_SECURITY_SIGNATURE
;
129 mb_put_uint16le(mbp
, flags2
);
130 if ((flags2
& SMB_FLAGS2_SECURITY_SIGNATURE
) == 0) {
131 mb_put_mem(mbp
, tzero
, 12, MB_MSYSTEM
);
132 rqp
->sr_rqsig
= NULL
;
134 mb_put_uint16le(mbp
, 0 /*scred->sc_p->p_pid >> 16*/);
135 rqp
->sr_rqsig
= (u_int8_t
*)mb_reserve(mbp
, 8);
136 mb_put_uint16le(mbp
, 0);
138 rqp
->sr_rqtid
= (u_int16_t
*)mb_reserve(mbp
, sizeof(u_int16_t
));
139 mb_put_uint16le(mbp
, 1 /*scred->sc_p->p_pid & 0xffff*/);
140 rqp
->sr_rquid
= (u_int16_t
*)mb_reserve(mbp
, sizeof(u_int16_t
));
141 mb_put_uint16le(mbp
, rqp
->sr_mid
);
146 smb_rq_done(struct smb_rq
*rqp
)
148 mb_done(&rqp
->sr_rq
);
149 md_done(&rqp
->sr_rp
);
150 smb_sl_destroy(&rqp
->sr_slock
);
151 if (rqp
->sr_flags
& SMBR_ALLOCED
)
156 * Simple request-reply exchange
159 smb_rq_simple(struct smb_rq
*rqp
)
161 struct smb_vc
*vcp
= rqp
->sr_vc
;
162 int error
= EINVAL
, i
;
164 for (i
= 0; i
< SMB_MAXRCN
; i
++) {
165 rqp
->sr_flags
&= ~SMBR_RESTART
;
166 rqp
->sr_timo
= vcp
->vc_timo
;
167 rqp
->sr_state
= SMBRQ_NOTSENT
;
168 error
= smb_rq_enqueue(rqp
);
171 error
= smb_rq_reply(rqp
);
174 if ((rqp
->sr_flags
& (SMBR_RESTART
| SMBR_NORESTART
)) != SMBR_RESTART
)
181 smb_rq_enqueue(struct smb_rq
*rqp
)
183 struct smb_share
*ssp
= rqp
->sr_share
;
186 if (ssp
== NULL
|| rqp
->sr_cred
== &rqp
->sr_vc
->vc_iod
->iod_scred
) {
187 return smb_iod_addrq(rqp
);
191 if (ssp
->ss_flags
& SMBS_RECONNECTING
) {
192 smb_sleep(&ssp
->ss_vcgenid
, SMBS_ST_INTERLOCK(ssp
),
193 PDROP
, "90trcn", hz
);
194 if (smb_proc_intr(rqp
->sr_cred
->scr_td
))
198 if (smb_share_valid(ssp
) || (ssp
->ss_flags
& SMBS_CONNECTED
) == 0) {
202 error
= smb_iod_request(rqp
->sr_vc
->vc_iod
,
203 SMBIOD_EV_TREECONNECT
| SMBIOD_EV_SYNC
, ssp
);
207 error
= smb_iod_addrq(rqp
);
215 smb_rq_wstart(struct smb_rq
*rqp
)
217 rqp
->sr_wcount
= mb_reserve(&rqp
->sr_rq
, sizeof(u_int8_t
));
218 rqp
->sr_rq
.mb_count
= 0;
222 smb_rq_wend(struct smb_rq
*rqp
)
224 if (rqp
->sr_wcount
== NULL
) {
225 SMBERROR("no wcount\n"); /* actually panic */
228 if (rqp
->sr_rq
.mb_count
& 1)
229 SMBERROR("odd word count\n");
230 *rqp
->sr_wcount
= rqp
->sr_rq
.mb_count
/ 2;
234 smb_rq_bstart(struct smb_rq
*rqp
)
236 rqp
->sr_bcount
= (u_short
*)mb_reserve(&rqp
->sr_rq
, sizeof(u_short
));
237 rqp
->sr_rq
.mb_count
= 0;
241 smb_rq_bend(struct smb_rq
*rqp
)
245 if (rqp
->sr_bcount
== NULL
) {
246 SMBERROR("no bcount\n"); /* actually panic */
249 bcnt
= rqp
->sr_rq
.mb_count
;
251 SMBERROR("byte count too large (%d)\n", bcnt
);
252 *rqp
->sr_bcount
= bcnt
;
256 smb_rq_intr(struct smb_rq
*rqp
)
258 struct thread
*td
= rqp
->sr_cred
->scr_td
;
260 if (rqp
->sr_flags
& SMBR_INTR
)
262 return smb_proc_intr(td
);
266 smb_rq_getrequest(struct smb_rq
*rqp
, struct mbchain
**mbpp
)
273 smb_rq_getreply(struct smb_rq
*rqp
, struct mdchain
**mbpp
)
280 smb_rq_getenv(struct smb_connobj
*layer
,
281 struct smb_vc
**vcpp
, struct smb_share
**sspp
)
283 struct smb_vc
*vcp
= NULL
;
284 struct smb_share
*ssp
= NULL
;
285 struct smb_connobj
*cp
;
288 switch (layer
->co_level
) {
291 if (layer
->co_parent
== NULL
) {
292 SMBERROR("zombie VC %s\n", vcp
->vc_srvname
);
299 cp
= layer
->co_parent
;
301 SMBERROR("zombie share %s\n", ssp
->ss_name
);
305 error
= smb_rq_getenv(cp
, &vcp
, NULL
);
310 SMBERROR("invalid layer %d passed\n", layer
->co_level
);
321 * Wait for reply on the request
324 smb_rq_reply(struct smb_rq
*rqp
)
326 struct mdchain
*mdp
= &rqp
->sr_rp
;
329 int error
, rperror
= 0;
331 error
= smb_iod_waitrq(rqp
);
334 error
= md_get_uint32(mdp
, &tdw
);
337 error
= md_get_uint8(mdp
, &tb
);
338 if (rqp
->sr_vc
->vc_hflags2
& SMB_FLAGS2_ERR_STATUS
) {
339 error
= md_get_uint32le(mdp
, &rqp
->sr_error
);
341 error
= md_get_uint8(mdp
, &rqp
->sr_errclass
);
342 error
= md_get_uint8(mdp
, &tb
);
343 error
= md_get_uint16le(mdp
, &rqp
->sr_serror
);
345 rperror
= smb_maperror(rqp
->sr_errclass
, rqp
->sr_serror
);
347 error
= md_get_uint8(mdp
, &rqp
->sr_rpflags
);
348 error
= md_get_uint16le(mdp
, &rqp
->sr_rpflags2
);
350 error
= md_get_uint32(mdp
, &tdw
);
351 error
= md_get_uint32(mdp
, &tdw
);
352 error
= md_get_uint32(mdp
, &tdw
);
354 error
= md_get_uint16le(mdp
, &rqp
->sr_rptid
);
355 error
= md_get_uint16le(mdp
, &rqp
->sr_rppid
);
356 error
= md_get_uint16le(mdp
, &rqp
->sr_rpuid
);
357 error
= md_get_uint16le(mdp
, &rqp
->sr_rpmid
);
360 (rqp
->sr_vc
->vc_hflags2
& SMB_FLAGS2_SECURITY_SIGNATURE
))
361 error
= smb_rq_verify(rqp
);
363 SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
364 rqp
->sr_rpmid
, rqp
->sr_rppid
, rqp
->sr_rpuid
, rqp
->sr_rptid
,
365 rqp
->sr_errclass
, rqp
->sr_serror
);
366 return error
? error
: rperror
;
370 #define ALIGN4(a) (((a) + 3) & ~3)
373 * TRANS2 request implementation
376 smb_t2_alloc(struct smb_connobj
*layer
, u_short setup
, struct smb_cred
*scred
,
377 struct smb_t2rq
**t2pp
)
379 struct smb_t2rq
*t2p
;
382 t2p
= kmalloc(sizeof(*t2p
), M_SMBRQ
, M_WAITOK
);
383 error
= smb_t2_init(t2p
, layer
, setup
, scred
);
384 t2p
->t2_flags
|= SMBT2_ALLOCED
;
394 smb_t2_init(struct smb_t2rq
*t2p
, struct smb_connobj
*source
, u_short setup
,
395 struct smb_cred
*scred
)
399 bzero(t2p
, sizeof(*t2p
));
400 t2p
->t2_source
= source
;
401 t2p
->t2_setupcount
= 1;
402 t2p
->t2_setupdata
= t2p
->t2_setup
;
403 t2p
->t2_setup
[0] = setup
;
404 t2p
->t2_fid
= 0xffff;
405 t2p
->t2_cred
= scred
;
406 error
= smb_rq_getenv(source
, &t2p
->t2_vc
, NULL
);
413 smb_t2_done(struct smb_t2rq
*t2p
)
415 mb_done(&t2p
->t2_tparam
);
416 mb_done(&t2p
->t2_tdata
);
417 md_done(&t2p
->t2_rparam
);
418 md_done(&t2p
->t2_rdata
);
419 if (t2p
->t2_flags
& SMBT2_ALLOCED
)
424 smb_t2_placedata(struct mbuf
*mtop
, u_int16_t offset
, u_int16_t count
,
430 m0
= m_split(mtop
, offset
, M_WAITOK
);
433 for(len
= 0, m
= m0
; m
->m_next
; m
= m
->m_next
)
436 m
->m_len
-= len
- count
;
437 if (mdp
->md_top
== NULL
) {
440 m_cat(mdp
->md_top
, m0
);
445 smb_t2_reply(struct smb_t2rq
*t2p
)
448 struct smb_rq
*rqp
= t2p
->t2_rq
;
449 int error
, totpgot
, totdgot
;
450 u_int16_t totpcount
, totdcount
, pcount
, poff
, doff
, pdisp
, ddisp
;
451 u_int16_t tmp
, bc
, dcount
;
454 error
= smb_rq_reply(rqp
);
457 if ((t2p
->t2_flags
& SMBT2_ALLSENT
) == 0) {
459 * this is an interim response, ignore it.
462 md_next_record(&rqp
->sr_rp
);
467 * Now we have to get all subsequent responses. The CIFS specification
468 * says that they can be disordered which is weird.
471 totpgot
= totdgot
= 0;
472 totpcount
= totdcount
= 0xffff;
475 m_dumpm(mdp
->md_top
);
476 if ((error
= md_get_uint8(mdp
, &wc
)) != 0)
482 if ((error
= md_get_uint16le(mdp
, &tmp
)) != 0)
486 md_get_uint16le(mdp
, &tmp
);
489 if ((error
= md_get_uint16le(mdp
, &tmp
)) != 0 || /* reserved */
490 (error
= md_get_uint16le(mdp
, &pcount
)) != 0 ||
491 (error
= md_get_uint16le(mdp
, &poff
)) != 0 ||
492 (error
= md_get_uint16le(mdp
, &pdisp
)) != 0)
494 if (pcount
!= 0 && pdisp
!= totpgot
) {
495 SMBERROR("Can't handle disordered parameters %d:%d\n",
500 if ((error
= md_get_uint16le(mdp
, &dcount
)) != 0 ||
501 (error
= md_get_uint16le(mdp
, &doff
)) != 0 ||
502 (error
= md_get_uint16le(mdp
, &ddisp
)) != 0)
504 if (dcount
!= 0 && ddisp
!= totdgot
) {
505 SMBERROR("Can't handle disordered data\n");
509 md_get_uint8(mdp
, &wc
);
510 md_get_uint8(mdp
, NULL
);
513 md_get_uint16(mdp
, NULL
);
514 if ((error
= md_get_uint16le(mdp
, &bc
)) != 0)
516 /* tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
518 error
= smb_t2_placedata(mdp
->md_top
, doff
, dcount
,
524 error
= smb_t2_placedata(mdp
->md_top
, poff
, pcount
,
531 if (totpgot
>= totpcount
&& totdgot
>= totdcount
) {
533 t2p
->t2_flags
|= SMBT2_ALLRECV
;
537 * We're done with this reply, look for the next one.
540 md_next_record(&rqp
->sr_rp
);
542 error
= smb_rq_reply(rqp
);
550 * Perform a full round of TRANS2 request
553 smb_t2_request_int(struct smb_t2rq
*t2p
)
555 struct smb_vc
*vcp
= t2p
->t2_vc
;
556 struct smb_cred
*scred
= t2p
->t2_cred
;
558 struct mdchain
*mdp
, mbparam
, mbdata
;
561 int totpcount
, leftpcount
, totdcount
, leftdcount
, len
, txmax
, i
;
562 int error
, doff
, poff
, txdcount
, txpcount
, nmlen
;
564 m
= t2p
->t2_tparam
.mb_top
;
566 md_initm(&mbparam
, m
); /* do not free it! */
567 totpcount
= m_fixhdr(m
);
568 if (totpcount
> 0xffff) /* maxvalue for u_short */
572 m
= t2p
->t2_tdata
.mb_top
;
574 md_initm(&mbdata
, m
); /* do not free it! */
575 totdcount
= m_fixhdr(m
);
576 if (totdcount
> 0xffff)
580 leftdcount
= totdcount
;
581 leftpcount
= totpcount
;
582 txmax
= vcp
->vc_txmax
;
583 error
= smb_rq_alloc(t2p
->t2_source
, t2p
->t_name
?
584 SMB_COM_TRANSACTION
: SMB_COM_TRANSACTION2
, scred
, &rqp
);
587 rqp
->sr_flags
|= SMBR_MULTIPACKET
;
592 mb_put_uint16le(mbp
, totpcount
);
593 mb_put_uint16le(mbp
, totdcount
);
594 mb_put_uint16le(mbp
, t2p
->t2_maxpcount
);
595 mb_put_uint16le(mbp
, t2p
->t2_maxdcount
);
596 mb_put_uint8(mbp
, t2p
->t2_maxscount
);
597 mb_put_uint8(mbp
, 0); /* reserved */
598 mb_put_uint16le(mbp
, 0); /* flags */
599 mb_put_uint32le(mbp
, 0); /* Timeout */
600 mb_put_uint16le(mbp
, 0); /* reserved 2 */
601 len
= mb_fixhdr(mbp
);
603 * now we have known packet size as
604 * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
605 * and need to decide which parts should go into the first request
607 nmlen
= t2p
->t_name
? strlen(t2p
->t_name
) : 0;
608 len
= ALIGN4(len
+ 5 * 2 + t2p
->t2_setupcount
* 2 + 2 + nmlen
+ 1);
609 if (len
+ leftpcount
> txmax
) {
610 txpcount
= min(leftpcount
, txmax
- len
);
615 txpcount
= leftpcount
;
616 poff
= txpcount
? len
: 0;
617 len
= ALIGN4(len
+ txpcount
);
618 txdcount
= min(leftdcount
, txmax
- len
);
619 doff
= txdcount
? len
: 0;
621 leftpcount
-= txpcount
;
622 leftdcount
-= txdcount
;
623 mb_put_uint16le(mbp
, txpcount
);
624 mb_put_uint16le(mbp
, poff
);
625 mb_put_uint16le(mbp
, txdcount
);
626 mb_put_uint16le(mbp
, doff
);
627 mb_put_uint8(mbp
, t2p
->t2_setupcount
);
628 mb_put_uint8(mbp
, 0);
629 for (i
= 0; i
< t2p
->t2_setupcount
; i
++)
630 mb_put_uint16le(mbp
, t2p
->t2_setupdata
[i
]);
635 mb_put_mem(mbp
, t2p
->t_name
, nmlen
, MB_MSYSTEM
);
636 mb_put_uint8(mbp
, 0); /* terminating zero */
637 len
= mb_fixhdr(mbp
);
639 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
640 error
= md_get_mbuf(&mbparam
, txpcount
, &m
);
641 SMBSDEBUG("%d:%d:%d\n", error
, txpcount
, txmax
);
646 len
= mb_fixhdr(mbp
);
648 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
649 error
= md_get_mbuf(&mbdata
, txdcount
, &m
);
654 smb_rq_bend(rqp
); /* incredible, but thats it... */
655 error
= smb_rq_enqueue(rqp
);
658 if (leftpcount
== 0 && leftdcount
== 0)
659 t2p
->t2_flags
|= SMBT2_ALLSENT
;
660 error
= smb_t2_reply(t2p
);
663 while (leftpcount
|| leftdcount
) {
664 t2p
->t2_flags
|= SMBT2_SECONDARY
;
665 error
= smb_rq_new(rqp
, t2p
->t_name
?
666 SMB_COM_TRANSACTION_SECONDARY
: SMB_COM_TRANSACTION2_SECONDARY
);
671 mb_put_uint16le(mbp
, totpcount
);
672 mb_put_uint16le(mbp
, totdcount
);
673 len
= mb_fixhdr(mbp
);
675 * now we have known packet size as
676 * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
677 * and need to decide which parts should go into request
679 len
= ALIGN4(len
+ 6 * 2 + 2);
680 if (t2p
->t_name
== NULL
)
682 if (len
+ leftpcount
> txmax
) {
683 txpcount
= min(leftpcount
, txmax
- len
);
688 txpcount
= leftpcount
;
689 poff
= txpcount
? len
: 0;
690 len
= ALIGN4(len
+ txpcount
);
691 txdcount
= min(leftdcount
, txmax
- len
);
692 doff
= txdcount
? len
: 0;
694 mb_put_uint16le(mbp
, txpcount
);
695 mb_put_uint16le(mbp
, poff
);
696 mb_put_uint16le(mbp
, totpcount
- leftpcount
);
697 mb_put_uint16le(mbp
, txdcount
);
698 mb_put_uint16le(mbp
, doff
);
699 mb_put_uint16le(mbp
, totdcount
- leftdcount
);
700 leftpcount
-= txpcount
;
701 leftdcount
-= txdcount
;
702 if (t2p
->t_name
== NULL
)
703 mb_put_uint16le(mbp
, t2p
->t2_fid
);
706 mb_put_uint8(mbp
, 0); /* name */
707 len
= mb_fixhdr(mbp
);
709 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
710 error
= md_get_mbuf(&mbparam
, txpcount
, &m
);
715 len
= mb_fixhdr(mbp
);
717 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
718 error
= md_get_mbuf(&mbdata
, txdcount
, &m
);
724 rqp
->sr_state
= SMBRQ_NOTSENT
;
725 error
= smb_iod_request(vcp
->vc_iod
, SMBIOD_EV_NEWRQ
, NULL
);
728 } /* while left params or data */
729 t2p
->t2_flags
|= SMBT2_ALLSENT
;
730 mdp
= &t2p
->t2_rdata
;
732 m_fixhdr(mdp
->md_top
);
733 md_initm(mdp
, mdp
->md_top
);
735 mdp
= &t2p
->t2_rparam
;
737 m_fixhdr(mdp
->md_top
);
738 md_initm(mdp
, mdp
->md_top
);
741 smb_iod_removerq(rqp
);
745 if (rqp
->sr_flags
& SMBR_RESTART
)
746 t2p
->t2_flags
|= SMBT2_RESTART
;
747 md_done(&t2p
->t2_rparam
);
748 md_done(&t2p
->t2_rdata
);
754 smb_t2_request(struct smb_t2rq
*t2p
)
756 int error
= EINVAL
, i
;
758 for (i
= 0; i
< SMB_MAXRCN
; i
++) {
759 t2p
->t2_flags
&= ~SMBR_RESTART
;
760 error
= smb_t2_request_int(t2p
);
763 if ((t2p
->t2_flags
& (SMBT2_RESTART
| SMBT2_NORESTART
)) != SMBT2_RESTART
)