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 $
33 * $DragonFly: src/sys/netproto/smb/smb_rq.c,v 1.11 2008/01/06 16:55:53 swildner Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
41 #include <sys/sysctl.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
52 MALLOC_DEFINE(M_SMBRQ
, "SMBRQ", "SMB request");
54 MODULE_DEPEND(netsmb
, libmchain
, 1, 1, 1);
56 static int smb_rq_reply(struct smb_rq
*rqp
);
57 static int smb_rq_enqueue(struct smb_rq
*rqp
);
58 static int smb_rq_getenv(struct smb_connobj
*layer
,
59 struct smb_vc
**vcpp
, struct smb_share
**sspp
);
60 static int smb_rq_new(struct smb_rq
*rqp
, u_char cmd
);
61 static int smb_t2_reply(struct smb_t2rq
*t2p
);
64 smb_rq_alloc(struct smb_connobj
*layer
, u_char cmd
, struct smb_cred
*scred
,
70 MALLOC(rqp
, struct smb_rq
*, sizeof(*rqp
), M_SMBRQ
, M_WAITOK
);
71 error
= smb_rq_init(rqp
, layer
, cmd
, scred
);
72 rqp
->sr_flags
|= SMBR_ALLOCED
;
81 static char tzero
[12];
84 smb_rq_init(struct smb_rq
*rqp
, struct smb_connobj
*layer
, u_char cmd
,
85 struct smb_cred
*scred
)
89 bzero(rqp
, sizeof(*rqp
));
90 smb_sl_init(&rqp
->sr_slock
, "srslock");
91 error
= smb_rq_getenv(layer
, &rqp
->sr_vc
, &rqp
->sr_share
);
94 error
= smb_vc_access(rqp
->sr_vc
, scred
, SMBM_EXEC
);
98 error
= smb_share_access(rqp
->sr_share
, scred
, SMBM_EXEC
);
102 rqp
->sr_cred
= scred
;
103 rqp
->sr_mid
= smb_vc_nextmid(rqp
->sr_vc
);
104 return smb_rq_new(rqp
, cmd
);
108 smb_rq_new(struct smb_rq
*rqp
, u_char cmd
)
110 struct smb_vc
*vcp
= rqp
->sr_vc
;
111 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 mb_put_uint16le(mbp
, vcp
->vc_hflags2
);
125 mb_put_mem(mbp
, tzero
, 12, MB_MSYSTEM
);
126 rqp
->sr_rqtid
= (u_int16_t
*)mb_reserve(mbp
, sizeof(u_int16_t
));
127 mb_put_uint16le(mbp
, 1 /*scred->sc_p->p_pid & 0xffff*/);
128 rqp
->sr_rquid
= (u_int16_t
*)mb_reserve(mbp
, sizeof(u_int16_t
));
129 mb_put_uint16le(mbp
, rqp
->sr_mid
);
134 smb_rq_done(struct smb_rq
*rqp
)
136 mb_done(&rqp
->sr_rq
);
137 md_done(&rqp
->sr_rp
);
138 smb_sl_destroy(&rqp
->sr_slock
);
139 if (rqp
->sr_flags
& SMBR_ALLOCED
)
144 * Simple request-reply exchange
147 smb_rq_simple(struct smb_rq
*rqp
)
149 struct smb_vc
*vcp
= rqp
->sr_vc
;
150 int error
= EINVAL
, i
;
152 for (i
= 0; i
< SMB_MAXRCN
; i
++) {
153 rqp
->sr_flags
&= ~SMBR_RESTART
;
154 rqp
->sr_timo
= vcp
->vc_timo
;
155 rqp
->sr_state
= SMBRQ_NOTSENT
;
156 error
= smb_rq_enqueue(rqp
);
159 error
= smb_rq_reply(rqp
);
162 if ((rqp
->sr_flags
& (SMBR_RESTART
| SMBR_NORESTART
)) != SMBR_RESTART
)
169 smb_rq_enqueue(struct smb_rq
*rqp
)
171 struct smb_share
*ssp
= rqp
->sr_share
;
174 if (ssp
== NULL
|| rqp
->sr_cred
== &rqp
->sr_vc
->vc_iod
->iod_scred
) {
175 return smb_iod_addrq(rqp
);
179 if (ssp
->ss_flags
& SMBS_RECONNECTING
) {
180 smb_sleep(&ssp
->ss_vcgenid
, SMBS_ST_INTERLOCK(ssp
),
181 PDROP
, "90trcn", hz
);
182 if (smb_proc_intr(rqp
->sr_cred
->scr_td
))
186 if (smb_share_valid(ssp
) || (ssp
->ss_flags
& SMBS_CONNECTED
) == 0) {
190 error
= smb_iod_request(rqp
->sr_vc
->vc_iod
,
191 SMBIOD_EV_TREECONNECT
| SMBIOD_EV_SYNC
, ssp
);
195 error
= smb_iod_addrq(rqp
);
203 smb_rq_wstart(struct smb_rq
*rqp
)
205 rqp
->sr_wcount
= mb_reserve(&rqp
->sr_rq
, sizeof(u_int8_t
));
206 rqp
->sr_rq
.mb_count
= 0;
210 smb_rq_wend(struct smb_rq
*rqp
)
212 if (rqp
->sr_wcount
== NULL
) {
213 SMBERROR("no wcount\n"); /* actually panic */
216 if (rqp
->sr_rq
.mb_count
& 1)
217 SMBERROR("odd word count\n");
218 *rqp
->sr_wcount
= rqp
->sr_rq
.mb_count
/ 2;
222 smb_rq_bstart(struct smb_rq
*rqp
)
224 rqp
->sr_bcount
= (u_short
*)mb_reserve(&rqp
->sr_rq
, sizeof(u_short
));
225 rqp
->sr_rq
.mb_count
= 0;
229 smb_rq_bend(struct smb_rq
*rqp
)
233 if (rqp
->sr_bcount
== NULL
) {
234 SMBERROR("no bcount\n"); /* actually panic */
237 bcnt
= rqp
->sr_rq
.mb_count
;
239 SMBERROR("byte count too large (%d)\n", bcnt
);
240 *rqp
->sr_bcount
= bcnt
;
244 smb_rq_intr(struct smb_rq
*rqp
)
246 struct thread
*td
= rqp
->sr_cred
->scr_td
;
248 if (rqp
->sr_flags
& SMBR_INTR
)
250 return smb_proc_intr(td
);
254 smb_rq_getrequest(struct smb_rq
*rqp
, struct mbchain
**mbpp
)
261 smb_rq_getreply(struct smb_rq
*rqp
, struct mdchain
**mbpp
)
268 smb_rq_getenv(struct smb_connobj
*layer
,
269 struct smb_vc
**vcpp
, struct smb_share
**sspp
)
271 struct smb_vc
*vcp
= NULL
;
272 struct smb_share
*ssp
= NULL
;
273 struct smb_connobj
*cp
;
276 switch (layer
->co_level
) {
279 if (layer
->co_parent
== NULL
) {
280 SMBERROR("zombie VC %s\n", vcp
->vc_srvname
);
287 cp
= layer
->co_parent
;
289 SMBERROR("zombie share %s\n", ssp
->ss_name
);
293 error
= smb_rq_getenv(cp
, &vcp
, NULL
);
298 SMBERROR("invalid layer %d passed\n", layer
->co_level
);
309 * Wait for reply on the request
312 smb_rq_reply(struct smb_rq
*rqp
)
314 struct mdchain
*mdp
= &rqp
->sr_rp
;
317 int error
, rperror
= 0;
319 error
= smb_iod_waitrq(rqp
);
322 error
= md_get_uint32(mdp
, &tdw
);
325 error
= md_get_uint8(mdp
, &tb
);
326 if (rqp
->sr_vc
->vc_hflags2
& SMB_FLAGS2_ERR_STATUS
) {
327 error
= md_get_uint32le(mdp
, &rqp
->sr_error
);
329 error
= md_get_uint8(mdp
, &rqp
->sr_errclass
);
330 error
= md_get_uint8(mdp
, &tb
);
331 error
= md_get_uint16le(mdp
, &rqp
->sr_serror
);
333 rperror
= smb_maperror(rqp
->sr_errclass
, rqp
->sr_serror
);
335 error
= md_get_uint8(mdp
, &rqp
->sr_rpflags
);
336 error
= md_get_uint16le(mdp
, &rqp
->sr_rpflags2
);
338 error
= md_get_uint32(mdp
, &tdw
);
339 error
= md_get_uint32(mdp
, &tdw
);
340 error
= md_get_uint32(mdp
, &tdw
);
342 error
= md_get_uint16le(mdp
, &rqp
->sr_rptid
);
343 error
= md_get_uint16le(mdp
, &rqp
->sr_rppid
);
344 error
= md_get_uint16le(mdp
, &rqp
->sr_rpuid
);
345 error
= md_get_uint16le(mdp
, &rqp
->sr_rpmid
);
347 SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n",
348 rqp
->sr_rpmid
, rqp
->sr_rppid
, rqp
->sr_rpuid
, rqp
->sr_rptid
,
349 rqp
->sr_errclass
, rqp
->sr_serror
);
350 return error
? error
: rperror
;
354 #define ALIGN4(a) (((a) + 3) & ~3)
357 * TRANS2 request implementation
360 smb_t2_alloc(struct smb_connobj
*layer
, u_short setup
, struct smb_cred
*scred
,
361 struct smb_t2rq
**t2pp
)
363 struct smb_t2rq
*t2p
;
366 MALLOC(t2p
, struct smb_t2rq
*, sizeof(*t2p
), M_SMBRQ
, M_WAITOK
);
367 error
= smb_t2_init(t2p
, layer
, setup
, scred
);
368 t2p
->t2_flags
|= SMBT2_ALLOCED
;
378 smb_t2_init(struct smb_t2rq
*t2p
, struct smb_connobj
*source
, u_short setup
,
379 struct smb_cred
*scred
)
383 bzero(t2p
, sizeof(*t2p
));
384 t2p
->t2_source
= source
;
385 t2p
->t2_setupcount
= 1;
386 t2p
->t2_setupdata
= t2p
->t2_setup
;
387 t2p
->t2_setup
[0] = setup
;
388 t2p
->t2_fid
= 0xffff;
389 t2p
->t2_cred
= scred
;
390 error
= smb_rq_getenv(source
, &t2p
->t2_vc
, NULL
);
397 smb_t2_done(struct smb_t2rq
*t2p
)
399 mb_done(&t2p
->t2_tparam
);
400 mb_done(&t2p
->t2_tdata
);
401 md_done(&t2p
->t2_rparam
);
402 md_done(&t2p
->t2_rdata
);
403 if (t2p
->t2_flags
& SMBT2_ALLOCED
)
408 smb_t2_placedata(struct mbuf
*mtop
, u_int16_t offset
, u_int16_t count
,
414 m0
= m_split(mtop
, offset
, MB_WAIT
);
417 for(len
= 0, m
= m0
; m
->m_next
; m
= m
->m_next
)
420 m
->m_len
-= len
- count
;
421 if (mdp
->md_top
== NULL
) {
424 m_cat(mdp
->md_top
, m0
);
429 smb_t2_reply(struct smb_t2rq
*t2p
)
432 struct smb_rq
*rqp
= t2p
->t2_rq
;
433 int error
, totpgot
, totdgot
;
434 u_int16_t totpcount
, totdcount
, pcount
, poff
, doff
, pdisp
, ddisp
;
435 u_int16_t tmp
, bc
, dcount
;
438 error
= smb_rq_reply(rqp
);
441 if ((t2p
->t2_flags
& SMBT2_ALLSENT
) == 0) {
443 * this is an interim response, ignore it.
446 md_next_record(&rqp
->sr_rp
);
451 * Now we have to get all subsequent responses. The CIFS specification
452 * says that they can be disordered which is weird.
455 totpgot
= totdgot
= 0;
456 totpcount
= totdcount
= 0xffff;
459 m_dumpm(mdp
->md_top
);
460 if ((error
= md_get_uint8(mdp
, &wc
)) != 0)
466 if ((error
= md_get_uint16le(mdp
, &tmp
)) != 0)
470 md_get_uint16le(mdp
, &tmp
);
473 if ((error
= md_get_uint16le(mdp
, &tmp
)) != 0 || /* reserved */
474 (error
= md_get_uint16le(mdp
, &pcount
)) != 0 ||
475 (error
= md_get_uint16le(mdp
, &poff
)) != 0 ||
476 (error
= md_get_uint16le(mdp
, &pdisp
)) != 0)
478 if (pcount
!= 0 && pdisp
!= totpgot
) {
479 SMBERROR("Can't handle disordered parameters %d:%d\n",
484 if ((error
= md_get_uint16le(mdp
, &dcount
)) != 0 ||
485 (error
= md_get_uint16le(mdp
, &doff
)) != 0 ||
486 (error
= md_get_uint16le(mdp
, &ddisp
)) != 0)
488 if (dcount
!= 0 && ddisp
!= totdgot
) {
489 SMBERROR("Can't handle disordered data\n");
493 md_get_uint8(mdp
, &wc
);
494 md_get_uint8(mdp
, NULL
);
497 md_get_uint16(mdp
, NULL
);
498 if ((error
= md_get_uint16le(mdp
, &bc
)) != 0)
500 /* tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
502 error
= smb_t2_placedata(mdp
->md_top
, doff
, dcount
,
508 error
= smb_t2_placedata(mdp
->md_top
, poff
, pcount
,
515 if (totpgot
>= totpcount
&& totdgot
>= totdcount
) {
517 t2p
->t2_flags
|= SMBT2_ALLRECV
;
521 * We're done with this reply, look for the next one.
524 md_next_record(&rqp
->sr_rp
);
526 error
= smb_rq_reply(rqp
);
534 * Perform a full round of TRANS2 request
537 smb_t2_request_int(struct smb_t2rq
*t2p
)
539 struct smb_vc
*vcp
= t2p
->t2_vc
;
540 struct smb_cred
*scred
= t2p
->t2_cred
;
542 struct mdchain
*mdp
, mbparam
, mbdata
;
545 int totpcount
, leftpcount
, totdcount
, leftdcount
, len
, txmax
, i
;
546 int error
, doff
, poff
, txdcount
, txpcount
, nmlen
;
548 m
= t2p
->t2_tparam
.mb_top
;
550 md_initm(&mbparam
, m
); /* do not free it! */
551 totpcount
= m_fixhdr(m
);
552 if (totpcount
> 0xffff) /* maxvalue for u_short */
556 m
= t2p
->t2_tdata
.mb_top
;
558 md_initm(&mbdata
, m
); /* do not free it! */
559 totdcount
= m_fixhdr(m
);
560 if (totdcount
> 0xffff)
564 leftdcount
= totdcount
;
565 leftpcount
= totpcount
;
566 txmax
= vcp
->vc_txmax
;
567 error
= smb_rq_alloc(t2p
->t2_source
, t2p
->t_name
?
568 SMB_COM_TRANSACTION
: SMB_COM_TRANSACTION2
, scred
, &rqp
);
571 rqp
->sr_flags
|= SMBR_MULTIPACKET
;
575 mb_put_uint16le(mbp
, totpcount
);
576 mb_put_uint16le(mbp
, totdcount
);
577 mb_put_uint16le(mbp
, t2p
->t2_maxpcount
);
578 mb_put_uint16le(mbp
, t2p
->t2_maxdcount
);
579 mb_put_uint8(mbp
, t2p
->t2_maxscount
);
580 mb_put_uint8(mbp
, 0); /* reserved */
581 mb_put_uint16le(mbp
, 0); /* flags */
582 mb_put_uint32le(mbp
, 0); /* Timeout */
583 mb_put_uint16le(mbp
, 0); /* reserved 2 */
584 len
= mb_fixhdr(mbp
);
586 * now we have known packet size as
587 * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
588 * and need to decide which parts should go into the first request
590 nmlen
= t2p
->t_name
? strlen(t2p
->t_name
) : 0;
591 len
= ALIGN4(len
+ 5 * 2 + t2p
->t2_setupcount
* 2 + 2 + nmlen
+ 1);
592 if (len
+ leftpcount
> txmax
) {
593 txpcount
= min(leftpcount
, txmax
- len
);
598 txpcount
= leftpcount
;
599 poff
= txpcount
? len
: 0;
600 len
= ALIGN4(len
+ txpcount
);
601 txdcount
= min(leftdcount
, txmax
- len
);
602 doff
= txdcount
? len
: 0;
604 leftpcount
-= txpcount
;
605 leftdcount
-= txdcount
;
606 mb_put_uint16le(mbp
, txpcount
);
607 mb_put_uint16le(mbp
, poff
);
608 mb_put_uint16le(mbp
, txdcount
);
609 mb_put_uint16le(mbp
, doff
);
610 mb_put_uint8(mbp
, t2p
->t2_setupcount
);
611 mb_put_uint8(mbp
, 0);
612 for (i
= 0; i
< t2p
->t2_setupcount
; i
++)
613 mb_put_uint16le(mbp
, t2p
->t2_setupdata
[i
]);
618 mb_put_mem(mbp
, t2p
->t_name
, nmlen
, MB_MSYSTEM
);
619 mb_put_uint8(mbp
, 0); /* terminating zero */
620 len
= mb_fixhdr(mbp
);
622 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
623 error
= md_get_mbuf(&mbparam
, txpcount
, &m
);
624 SMBSDEBUG("%d:%d:%d\n", error
, txpcount
, txmax
);
629 len
= mb_fixhdr(mbp
);
631 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
632 error
= md_get_mbuf(&mbdata
, txdcount
, &m
);
637 smb_rq_bend(rqp
); /* incredible, but thats it... */
638 error
= smb_rq_enqueue(rqp
);
641 if (leftpcount
== 0 && leftdcount
== 0)
642 t2p
->t2_flags
|= SMBT2_ALLSENT
;
643 error
= smb_t2_reply(t2p
);
646 while (leftpcount
|| leftdcount
) {
647 error
= smb_rq_new(rqp
, t2p
->t_name
?
648 SMB_COM_TRANSACTION_SECONDARY
: SMB_COM_TRANSACTION2_SECONDARY
);
653 mb_put_uint16le(mbp
, totpcount
);
654 mb_put_uint16le(mbp
, totdcount
);
655 len
= mb_fixhdr(mbp
);
657 * now we have known packet size as
658 * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
659 * and need to decide which parts should go into request
661 len
= ALIGN4(len
+ 6 * 2 + 2);
662 if (t2p
->t_name
== NULL
)
664 if (len
+ leftpcount
> txmax
) {
665 txpcount
= min(leftpcount
, txmax
- len
);
670 txpcount
= leftpcount
;
671 poff
= txpcount
? len
: 0;
672 len
= ALIGN4(len
+ txpcount
);
673 txdcount
= min(leftdcount
, txmax
- len
);
674 doff
= txdcount
? len
: 0;
676 mb_put_uint16le(mbp
, txpcount
);
677 mb_put_uint16le(mbp
, poff
);
678 mb_put_uint16le(mbp
, totpcount
- leftpcount
);
679 mb_put_uint16le(mbp
, txdcount
);
680 mb_put_uint16le(mbp
, doff
);
681 mb_put_uint16le(mbp
, totdcount
- leftdcount
);
682 leftpcount
-= txpcount
;
683 leftdcount
-= txdcount
;
684 if (t2p
->t_name
== NULL
)
685 mb_put_uint16le(mbp
, t2p
->t2_fid
);
688 mb_put_uint8(mbp
, 0); /* name */
689 len
= mb_fixhdr(mbp
);
691 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
692 error
= md_get_mbuf(&mbparam
, txpcount
, &m
);
697 len
= mb_fixhdr(mbp
);
699 mb_put_mem(mbp
, NULL
, ALIGN4(len
) - len
, MB_MZERO
);
700 error
= md_get_mbuf(&mbdata
, txdcount
, &m
);
706 rqp
->sr_state
= SMBRQ_NOTSENT
;
707 error
= smb_iod_request(vcp
->vc_iod
, SMBIOD_EV_NEWRQ
, NULL
);
710 } /* while left params or data */
711 t2p
->t2_flags
|= SMBT2_ALLSENT
;
712 mdp
= &t2p
->t2_rdata
;
714 m_fixhdr(mdp
->md_top
);
715 md_initm(mdp
, mdp
->md_top
);
717 mdp
= &t2p
->t2_rparam
;
719 m_fixhdr(mdp
->md_top
);
720 md_initm(mdp
, mdp
->md_top
);
723 smb_iod_removerq(rqp
);
727 if (rqp
->sr_flags
& SMBR_RESTART
)
728 t2p
->t2_flags
|= SMBT2_RESTART
;
729 md_done(&t2p
->t2_rparam
);
730 md_done(&t2p
->t2_rdata
);
736 smb_t2_request(struct smb_t2rq
*t2p
)
738 int error
= EINVAL
, i
;
740 for (i
= 0; i
< SMB_MAXRCN
; i
++) {
741 t2p
->t2_flags
&= ~SMBR_RESTART
;
742 error
= smb_t2_request_int(t2p
);
745 if ((t2p
->t2_flags
& (SMBT2_RESTART
| SMBT2_NORESTART
)) != SMBT2_RESTART
)