]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netsmb/smb_rq.c
sysctl(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sys / netsmb / smb_rq.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2000-2001 Boris Popov
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/endian.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
38 #include <sys/proc.h>
39 #include <sys/lock.h>
40 #include <sys/sysctl.h>
41 #include <sys/socket.h>
42 #include <sys/socketvar.h>
43 #include <sys/mbuf.h>
44
45 #include <netsmb/smb.h>
46 #include <netsmb/smb_conn.h>
47 #include <netsmb/smb_rq.h>
48 #include <netsmb/smb_subr.h>
49 #include <netsmb/smb_tran.h>
50
51 static MALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request");
52
53 MODULE_DEPEND(netsmb, libmchain, 1, 1, 1);
54
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);
61
62 int
63 smb_rq_alloc(struct smb_connobj *layer, u_char cmd, struct smb_cred *scred,
64         struct smb_rq **rqpp)
65 {
66         struct smb_rq *rqp;
67         int error;
68
69         rqp = malloc(sizeof(*rqp), M_SMBRQ, M_WAITOK);
70         if (rqp == NULL)
71                 return ENOMEM;
72         error = smb_rq_init(rqp, layer, cmd, scred);
73         rqp->sr_flags |= SMBR_ALLOCED;
74         if (error) {
75                 smb_rq_done(rqp);
76                 return error;
77         }
78         *rqpp = rqp;
79         return 0;
80 }
81
82 static char tzero[12];
83
84 int
85 smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd,
86         struct smb_cred *scred)
87 {
88         int error;
89
90         bzero(rqp, sizeof(*rqp));
91         smb_sl_init(&rqp->sr_slock, "srslock");
92         error = smb_rq_getenv(layer, &rqp->sr_vc, &rqp->sr_share);
93         if (error)
94                 return error;
95         error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC);
96         if (error)
97                 return error;
98         if (rqp->sr_share) {
99                 error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC);
100                 if (error)
101                         return error;
102         }
103         rqp->sr_cred = scred;
104         rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
105         return smb_rq_new(rqp, cmd);
106 }
107
108 static int
109 smb_rq_new(struct smb_rq *rqp, u_char cmd)
110 {
111         struct smb_vc *vcp = rqp->sr_vc;
112         struct mbchain *mbp = &rqp->sr_rq;
113         int error;
114         u_int16_t flags2;
115
116         rqp->sr_sendcnt = 0;
117         mb_done(mbp);
118         md_done(&rqp->sr_rp);
119         error = mb_init(mbp);
120         if (error)
121                 return error;
122         mb_put_mem(mbp, SMB_SIGNATURE, SMB_SIGLEN, MB_MSYSTEM);
123         mb_put_uint8(mbp, cmd);
124         mb_put_uint32le(mbp, 0);                /* DosError */
125         mb_put_uint8(mbp, vcp->vc_hflags);
126         flags2 = vcp->vc_hflags2;
127         if (cmd == SMB_COM_TRANSACTION || cmd == SMB_COM_TRANSACTION_SECONDARY)
128                 flags2 &= ~SMB_FLAGS2_UNICODE;
129         if (cmd == SMB_COM_NEGOTIATE)
130                 flags2 &= ~SMB_FLAGS2_SECURITY_SIGNATURE;
131         mb_put_uint16le(mbp, flags2);
132         if ((flags2 & SMB_FLAGS2_SECURITY_SIGNATURE) == 0) {
133                 mb_put_mem(mbp, tzero, 12, MB_MSYSTEM);
134                 rqp->sr_rqsig = NULL;
135         } else {
136                 mb_put_uint16le(mbp, 0 /*scred->sc_p->p_pid >> 16*/);
137                 rqp->sr_rqsig = (u_int8_t *)mb_reserve(mbp, 8);
138                 mb_put_uint16le(mbp, 0);
139         }
140         rqp->sr_rqtid = mb_reserve(mbp, sizeof(u_int16_t));
141         mb_put_uint16le(mbp, 1 /*scred->sc_p->p_pid & 0xffff*/);
142         rqp->sr_rquid = mb_reserve(mbp, sizeof(u_int16_t));
143         mb_put_uint16le(mbp, rqp->sr_mid);
144         return 0;
145 }
146
147 void
148 smb_rq_done(struct smb_rq *rqp)
149 {
150         mb_done(&rqp->sr_rq);
151         md_done(&rqp->sr_rp);
152         smb_sl_destroy(&rqp->sr_slock);
153         if (rqp->sr_flags & SMBR_ALLOCED)
154                 free(rqp, M_SMBRQ);
155 }
156
157 /*
158  * Simple request-reply exchange
159  */
160 int
161 smb_rq_simple(struct smb_rq *rqp)
162 {
163         struct smb_vc *vcp = rqp->sr_vc;
164         int error = EINVAL, i;
165
166         for (i = 0; i < SMB_MAXRCN; i++) {
167                 rqp->sr_flags &= ~SMBR_RESTART;
168                 rqp->sr_timo = vcp->vc_timo;
169                 rqp->sr_state = SMBRQ_NOTSENT;
170                 error = smb_rq_enqueue(rqp);
171                 if (error)
172                         return error;
173                 error = smb_rq_reply(rqp);
174                 if (error == 0)
175                         break;
176                 if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART)
177                         break;
178         }
179         return error;
180 }
181
182 static int
183 smb_rq_enqueue(struct smb_rq *rqp)
184 {
185         struct smb_share *ssp = rqp->sr_share;
186         int error;
187
188         if (ssp == NULL || rqp->sr_cred == &rqp->sr_vc->vc_iod->iod_scred) {
189                 return smb_iod_addrq(rqp);
190         }
191         for (;;) {
192                 SMBS_ST_LOCK(ssp);
193                 if (ssp->ss_flags & SMBS_RECONNECTING) {
194                         msleep(&ssp->ss_vcgenid, SMBS_ST_LOCKPTR(ssp),
195                             PWAIT | PDROP, "90trcn", hz);
196                         if (smb_td_intr(rqp->sr_cred->scr_td))
197                                 return EINTR;
198                         continue;
199                 }
200                 if (smb_share_valid(ssp) || (ssp->ss_flags & SMBS_CONNECTED) == 0) {
201                         SMBS_ST_UNLOCK(ssp);
202                 } else {
203                         SMBS_ST_UNLOCK(ssp);
204                         error = smb_iod_request(rqp->sr_vc->vc_iod,
205                             SMBIOD_EV_TREECONNECT | SMBIOD_EV_SYNC, ssp);
206                         if (error)
207                                 return error;
208                 }
209                 error = smb_iod_addrq(rqp);
210                 if (error != EXDEV)
211                         break;
212         }
213         return error;
214 }
215
216 void
217 smb_rq_wstart(struct smb_rq *rqp)
218 {
219         rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof(u_int8_t));
220         rqp->sr_rq.mb_count = 0;
221 }
222
223 void
224 smb_rq_wend(struct smb_rq *rqp)
225 {
226         if (rqp->sr_wcount == NULL) {
227                 SMBERROR("no wcount\n");        /* actually panic */
228                 return;
229         }
230         if (rqp->sr_rq.mb_count & 1)
231                 SMBERROR("odd word count\n");
232         *rqp->sr_wcount = rqp->sr_rq.mb_count / 2;
233 }
234
235 void
236 smb_rq_bstart(struct smb_rq *rqp)
237 {
238         rqp->sr_bcount = mb_reserve(&rqp->sr_rq, sizeof(u_short));
239         rqp->sr_rq.mb_count = 0;
240 }
241
242 void
243 smb_rq_bend(struct smb_rq *rqp)
244 {
245         int bcnt;
246
247         if (rqp->sr_bcount == NULL) {
248                 SMBERROR("no bcount\n");        /* actually panic */
249                 return;
250         }
251         bcnt = rqp->sr_rq.mb_count;
252         if (bcnt > 0xffff)
253                 SMBERROR("byte count too large (%d)\n", bcnt);
254         le16enc(rqp->sr_bcount, bcnt);
255 }
256
257 int
258 smb_rq_intr(struct smb_rq *rqp)
259 {
260         if (rqp->sr_flags & SMBR_INTR)
261                 return EINTR;
262         return smb_td_intr(rqp->sr_cred->scr_td);
263 }
264
265 int
266 smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
267 {
268         *mbpp = &rqp->sr_rq;
269         return 0;
270 }
271
272 int
273 smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
274 {
275         *mbpp = &rqp->sr_rp;
276         return 0;
277 }
278
279 static int
280 smb_rq_getenv(struct smb_connobj *layer,
281         struct smb_vc **vcpp, struct smb_share **sspp)
282 {
283         struct smb_vc *vcp = NULL;
284         struct smb_share *ssp = NULL;
285         struct smb_connobj *cp;
286         int error = 0;
287
288         switch (layer->co_level) {
289             case SMBL_VC:
290                 vcp = CPTOVC(layer);
291                 if (layer->co_parent == NULL) {
292                         SMBERROR("zombie VC %s\n", vcp->vc_srvname);
293                         error = EINVAL;
294                         break;
295                 }
296                 break;
297             case SMBL_SHARE:
298                 ssp = CPTOSS(layer);
299                 cp = layer->co_parent;
300                 if (cp == NULL) {
301                         SMBERROR("zombie share %s\n", ssp->ss_name);
302                         error = EINVAL;
303                         break;
304                 }
305                 error = smb_rq_getenv(cp, &vcp, NULL);
306                 if (error)
307                         break;
308                 break;
309             default:
310                 SMBERROR("invalid layer %d passed\n", layer->co_level);
311                 error = EINVAL;
312         }
313         if (vcpp)
314                 *vcpp = vcp;
315         if (sspp)
316                 *sspp = ssp;
317         return error;
318 }
319
320 /*
321  * Wait for reply on the request
322  */
323 static int
324 smb_rq_reply(struct smb_rq *rqp)
325 {
326         struct mdchain *mdp = &rqp->sr_rp;
327         u_int32_t tdw;
328         u_int8_t tb;
329         int error, rperror = 0;
330
331         error = smb_iod_waitrq(rqp);
332         if (error)
333                 return error;
334         error = md_get_uint32(mdp, &tdw);
335         if (error)
336                 return error;
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);
340         } else {
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);
344                 if (!error)
345                         rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
346         }
347         error = md_get_uint8(mdp, &rqp->sr_rpflags);
348         error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
349
350         error = md_get_uint32(mdp, &tdw);
351         error = md_get_uint32(mdp, &tdw);
352         error = md_get_uint32(mdp, &tdw);
353
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);
358
359         if (error == 0 &&
360             (rqp->sr_vc->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE))
361                 error = smb_rq_verify(rqp);
362
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;
367 }
368
369 #define ALIGN4(a)       (((a) + 3) & ~3)
370
371 /*
372  * TRANS2 request implementation
373  */
374 int
375 smb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred,
376         struct smb_t2rq **t2pp)
377 {
378         struct smb_t2rq *t2p;
379         int error;
380
381         t2p = malloc(sizeof(*t2p), M_SMBRQ, M_WAITOK);
382         if (t2p == NULL)
383                 return ENOMEM;
384         error = smb_t2_init(t2p, layer, setup, scred);
385         t2p->t2_flags |= SMBT2_ALLOCED;
386         if (error) {
387                 smb_t2_done(t2p);
388                 return error;
389         }
390         *t2pp = t2p;
391         return 0;
392 }
393
394 int
395 smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, u_short setup,
396         struct smb_cred *scred)
397 {
398         int error;
399
400         bzero(t2p, sizeof(*t2p));
401         t2p->t2_source = source;
402         t2p->t2_setupcount = 1;
403         t2p->t2_setupdata = t2p->t2_setup;
404         t2p->t2_setup[0] = setup;
405         t2p->t2_fid = 0xffff;
406         t2p->t2_cred = scred;
407         error = smb_rq_getenv(source, &t2p->t2_vc, NULL);
408         if (error)
409                 return error;
410         return 0;
411 }
412
413 void
414 smb_t2_done(struct smb_t2rq *t2p)
415 {
416         mb_done(&t2p->t2_tparam);
417         mb_done(&t2p->t2_tdata);
418         md_done(&t2p->t2_rparam);
419         md_done(&t2p->t2_rdata);
420         if (t2p->t2_flags & SMBT2_ALLOCED)
421                 free(t2p, M_SMBRQ);
422 }
423
424 static int
425 smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count,
426         struct mdchain *mdp)
427 {
428         struct mbuf *m, *m0;
429         int len;
430
431         m0 = m_split(mtop, offset, M_WAITOK);
432         len = m_length(m0, &m);
433         m->m_len -= len - count;
434         if (mdp->md_top == NULL) {
435                 md_initm(mdp, m0);
436         } else
437                 m_cat(mdp->md_top, m0);
438         return 0;
439 }
440
441 static int
442 smb_t2_reply(struct smb_t2rq *t2p)
443 {
444         struct mdchain *mdp;
445         struct smb_rq *rqp = t2p->t2_rq;
446         int error, totpgot, totdgot;
447         u_int16_t totpcount, totdcount, pcount, poff, doff, pdisp, ddisp;
448         u_int16_t tmp, bc, dcount;
449         u_int8_t wc;
450
451         error = smb_rq_reply(rqp);
452         if (error)
453                 return error;
454         if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
455                 /* 
456                  * this is an interim response, ignore it.
457                  */
458                 SMBRQ_SLOCK(rqp);
459                 md_next_record(&rqp->sr_rp);
460                 SMBRQ_SUNLOCK(rqp);
461                 return 0;
462         }
463         /*
464          * Now we have to get all subsequent responses. The CIFS specification
465          * says that they can be disordered which is weird.
466          * TODO: timo
467          */
468         totpgot = totdgot = 0;
469         totpcount = totdcount = 0xffff;
470         mdp = &rqp->sr_rp;
471         for (;;) {
472                 m_dumpm(mdp->md_top);
473                 if ((error = md_get_uint8(mdp, &wc)) != 0)
474                         break;
475                 if (wc < 10) {
476                         error = ENOENT;
477                         break;
478                 }
479                 if ((error = md_get_uint16le(mdp, &tmp)) != 0)
480                         break;
481                 if (totpcount > tmp)
482                         totpcount = tmp;
483                 md_get_uint16le(mdp, &tmp);
484                 if (totdcount > tmp)
485                         totdcount = tmp;
486                 if ((error = md_get_uint16le(mdp, &tmp)) != 0 || /* reserved */
487                     (error = md_get_uint16le(mdp, &pcount)) != 0 ||
488                     (error = md_get_uint16le(mdp, &poff)) != 0 ||
489                     (error = md_get_uint16le(mdp, &pdisp)) != 0)
490                         break;
491                 if (pcount != 0 && pdisp != totpgot) {
492                         SMBERROR("Can't handle disordered parameters %d:%d\n",
493                             pdisp, totpgot);
494                         error = EINVAL;
495                         break;
496                 }
497                 if ((error = md_get_uint16le(mdp, &dcount)) != 0 ||
498                     (error = md_get_uint16le(mdp, &doff)) != 0 ||
499                     (error = md_get_uint16le(mdp, &ddisp)) != 0)
500                         break;
501                 if (dcount != 0 && ddisp != totdgot) {
502                         SMBERROR("Can't handle disordered data\n");
503                         error = EINVAL;
504                         break;
505                 }
506                 md_get_uint8(mdp, &wc);
507                 md_get_uint8(mdp, NULL);
508                 tmp = wc;
509                 while (tmp--)
510                         md_get_uint16(mdp, NULL);
511                 if ((error = md_get_uint16le(mdp, &bc)) != 0)
512                         break;
513 /*              tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
514                 if (dcount) {
515                         error = smb_t2_placedata(mdp->md_top, doff, dcount,
516                             &t2p->t2_rdata);
517                         if (error)
518                                 break;
519                 }
520                 if (pcount) {
521                         error = smb_t2_placedata(mdp->md_top, poff, pcount,
522                             &t2p->t2_rparam);
523                         if (error)
524                                 break;
525                 }
526                 totpgot += pcount;
527                 totdgot += dcount;
528                 if (totpgot >= totpcount && totdgot >= totdcount) {
529                         error = 0;
530                         t2p->t2_flags |= SMBT2_ALLRECV;
531                         break;
532                 }
533                 /*
534                  * We're done with this reply, look for the next one.
535                  */
536                 SMBRQ_SLOCK(rqp);
537                 md_next_record(&rqp->sr_rp);
538                 SMBRQ_SUNLOCK(rqp);
539                 error = smb_rq_reply(rqp);
540                 if (error)
541                         break;
542         }
543         return error;
544 }
545
546 /*
547  * Perform a full round of TRANS2 request
548  */
549 static int
550 smb_t2_request_int(struct smb_t2rq *t2p)
551 {
552         struct smb_vc *vcp = t2p->t2_vc;
553         struct smb_cred *scred = t2p->t2_cred;
554         struct mbchain *mbp;
555         struct mdchain *mdp, mbparam, mbdata;
556         struct mbuf *m;
557         struct smb_rq *rqp;
558         int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
559         int error, doff, poff, txdcount, txpcount, nmlen;
560
561         m = t2p->t2_tparam.mb_top;
562         if (m) {
563                 md_initm(&mbparam, m);  /* do not free it! */
564                 totpcount = m_fixhdr(m);
565                 if (totpcount > 0xffff)         /* maxvalue for u_short */
566                         return EINVAL;
567         } else
568                 totpcount = 0;
569         m = t2p->t2_tdata.mb_top;
570         if (m) {
571                 md_initm(&mbdata, m);   /* do not free it! */
572                 totdcount =  m_fixhdr(m);
573                 if (totdcount > 0xffff)
574                         return EINVAL;
575         } else
576                 totdcount = 0;
577         leftdcount = totdcount;
578         leftpcount = totpcount;
579         txmax = vcp->vc_txmax;
580         error = smb_rq_alloc(t2p->t2_source, t2p->t_name ?
581             SMB_COM_TRANSACTION : SMB_COM_TRANSACTION2, scred, &rqp);
582         if (error)
583                 return error;
584         rqp->sr_flags |= SMBR_MULTIPACKET;
585         t2p->t2_rq = rqp;
586         rqp->sr_t2 = t2p;
587         mbp = &rqp->sr_rq;
588         smb_rq_wstart(rqp);
589         mb_put_uint16le(mbp, totpcount);
590         mb_put_uint16le(mbp, totdcount);
591         mb_put_uint16le(mbp, t2p->t2_maxpcount);
592         mb_put_uint16le(mbp, t2p->t2_maxdcount);
593         mb_put_uint8(mbp, t2p->t2_maxscount);
594         mb_put_uint8(mbp, 0);                   /* reserved */
595         mb_put_uint16le(mbp, 0);                        /* flags */
596         mb_put_uint32le(mbp, 0);                        /* Timeout */
597         mb_put_uint16le(mbp, 0);                        /* reserved 2 */
598         len = mb_fixhdr(mbp);
599         /*
600          * now we have known packet size as
601          * ALIGN4(len + 5 * 2 + setupcount * 2 + 2 + strlen(name) + 1),
602          * and need to decide which parts should go into the first request
603          */
604         nmlen = t2p->t_name ? strlen(t2p->t_name) : 0;
605         len = ALIGN4(len + 5 * 2 + t2p->t2_setupcount * 2 + 2 + nmlen + 1);
606         if (len + leftpcount > txmax) {
607                 txpcount = min(leftpcount, txmax - len);
608                 poff = len;
609                 txdcount = 0;
610                 doff = 0;
611         } else {
612                 txpcount = leftpcount;
613                 poff = txpcount ? len : 0;
614                 len = ALIGN4(len + txpcount);
615                 txdcount = min(leftdcount, txmax - len);
616                 doff = txdcount ? len : 0;
617         }
618         leftpcount -= txpcount;
619         leftdcount -= txdcount;
620         mb_put_uint16le(mbp, txpcount);
621         mb_put_uint16le(mbp, poff);
622         mb_put_uint16le(mbp, txdcount);
623         mb_put_uint16le(mbp, doff);
624         mb_put_uint8(mbp, t2p->t2_setupcount);
625         mb_put_uint8(mbp, 0);
626         for (i = 0; i < t2p->t2_setupcount; i++)
627                 mb_put_uint16le(mbp, t2p->t2_setupdata[i]);
628         smb_rq_wend(rqp);
629         smb_rq_bstart(rqp);
630         /* TDUNICODE */
631         if (t2p->t_name)
632                 mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
633         mb_put_uint8(mbp, 0);   /* terminating zero */
634         len = mb_fixhdr(mbp);
635         if (txpcount) {
636                 mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
637                 error = md_get_mbuf(&mbparam, txpcount, &m);
638                 SMBSDEBUG("%d:%d:%d\n", error, txpcount, txmax);
639                 if (error)
640                         goto freerq;
641                 mb_put_mbuf(mbp, m);
642         }
643         len = mb_fixhdr(mbp);
644         if (txdcount) {
645                 mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
646                 error = md_get_mbuf(&mbdata, txdcount, &m);
647                 if (error)
648                         goto freerq;
649                 mb_put_mbuf(mbp, m);
650         }
651         smb_rq_bend(rqp);       /* incredible, but thats it... */
652         error = smb_rq_enqueue(rqp);
653         if (error)
654                 goto freerq;
655         if (leftpcount == 0 && leftdcount == 0)
656                 t2p->t2_flags |= SMBT2_ALLSENT;
657         error = smb_t2_reply(t2p);
658         if (error)
659                 goto bad;
660         while (leftpcount || leftdcount) {
661                 t2p->t2_flags |= SMBT2_SECONDARY;
662                 error = smb_rq_new(rqp, t2p->t_name ? 
663                     SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY);
664                 if (error)
665                         goto bad;
666                 mbp = &rqp->sr_rq;
667                 smb_rq_wstart(rqp);
668                 mb_put_uint16le(mbp, totpcount);
669                 mb_put_uint16le(mbp, totdcount);
670                 len = mb_fixhdr(mbp);
671                 /*
672                  * now we have known packet size as
673                  * ALIGN4(len + 7 * 2 + 2) for T2 request, and -2 for T one,
674                  * and need to decide which parts should go into request
675                  */
676                 len = ALIGN4(len + 6 * 2 + 2);
677                 if (t2p->t_name == NULL)
678                         len += 2;
679                 if (len + leftpcount > txmax) {
680                         txpcount = min(leftpcount, txmax - len);
681                         poff = len;
682                         txdcount = 0;
683                         doff = 0;
684                 } else {
685                         txpcount = leftpcount;
686                         poff = txpcount ? len : 0;
687                         len = ALIGN4(len + txpcount);
688                         txdcount = min(leftdcount, txmax - len);
689                         doff = txdcount ? len : 0;
690                 }
691                 mb_put_uint16le(mbp, txpcount);
692                 mb_put_uint16le(mbp, poff);
693                 mb_put_uint16le(mbp, totpcount - leftpcount);
694                 mb_put_uint16le(mbp, txdcount);
695                 mb_put_uint16le(mbp, doff);
696                 mb_put_uint16le(mbp, totdcount - leftdcount);
697                 leftpcount -= txpcount;
698                 leftdcount -= txdcount;
699                 if (t2p->t_name == NULL)
700                         mb_put_uint16le(mbp, t2p->t2_fid);
701                 smb_rq_wend(rqp);
702                 smb_rq_bstart(rqp);
703                 mb_put_uint8(mbp, 0);   /* name */
704                 len = mb_fixhdr(mbp);
705                 if (txpcount) {
706                         mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
707                         error = md_get_mbuf(&mbparam, txpcount, &m);
708                         if (error)
709                                 goto bad;
710                         mb_put_mbuf(mbp, m);
711                 }
712                 len = mb_fixhdr(mbp);
713                 if (txdcount) {
714                         mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
715                         error = md_get_mbuf(&mbdata, txdcount, &m);
716                         if (error)
717                                 goto bad;
718                         mb_put_mbuf(mbp, m);
719                 }
720                 smb_rq_bend(rqp);
721                 rqp->sr_state = SMBRQ_NOTSENT;
722                 error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL);
723                 if (error)
724                         goto bad;
725         }       /* while left params or data */
726         t2p->t2_flags |= SMBT2_ALLSENT;
727         mdp = &t2p->t2_rdata;
728         if (mdp->md_top) {
729                 m_fixhdr(mdp->md_top);
730                 md_initm(mdp, mdp->md_top);
731         }
732         mdp = &t2p->t2_rparam;
733         if (mdp->md_top) {
734                 m_fixhdr(mdp->md_top);
735                 md_initm(mdp, mdp->md_top);
736         }
737 bad:
738         smb_iod_removerq(rqp);
739 freerq:
740         smb_rq_done(rqp);
741         if (error) {
742                 if (rqp->sr_flags & SMBR_RESTART)
743                         t2p->t2_flags |= SMBT2_RESTART;
744                 md_done(&t2p->t2_rparam);
745                 md_done(&t2p->t2_rdata);
746         }
747         return error;
748 }
749
750 int
751 smb_t2_request(struct smb_t2rq *t2p)
752 {
753         int error = EINVAL, i;
754
755         for (i = 0; i < SMB_MAXRCN; i++) {
756                 t2p->t2_flags &= ~SMBR_RESTART;
757                 error = smb_t2_request_int(t2p);
758                 if (error == 0)
759                         break;
760                 if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART)
761                         break;
762         }
763         return error;
764 }