AMD64 - Refactor uio_resid and size_t assumptions.
[dragonfly.git] / sys / netproto / smb / smb_rq.c
1 /*
2  * Copyright (c) 2000-2001, Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
19  *
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
30  * SUCH DAMAGE.
31  *
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 $
34  */
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/proc.h>
40 #include <sys/lock.h>
41 #include <sys/sysctl.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/mbuf.h>
45
46 #include "smb.h"
47 #include "smb_conn.h"
48 #include "smb_rq.h"
49 #include "smb_subr.h"
50 #include "smb_tran.h"
51
52 MALLOC_DEFINE(M_SMBRQ, "SMBRQ", "SMB request");
53
54 MODULE_DEPEND(netsmb, libmchain, 1, 1, 1);
55
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);
62
63 int
64 smb_rq_alloc(struct smb_connobj *layer, u_char cmd, struct smb_cred *scred,
65         struct smb_rq **rqpp)
66 {
67         struct smb_rq *rqp;
68         int error;
69
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;
73         if (error) {
74                 smb_rq_done(rqp);
75                 return error;
76         }
77         *rqpp = rqp;
78         return 0;
79 }
80
81 static char tzero[12];
82
83 int
84 smb_rq_init(struct smb_rq *rqp, struct smb_connobj *layer, u_char cmd,
85         struct smb_cred *scred)
86 {
87         int error;
88
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);
92         if (error)
93                 return error;
94         error = smb_vc_access(rqp->sr_vc, scred, SMBM_EXEC);
95         if (error)
96                 return error;
97         if (rqp->sr_share) {
98                 error = smb_share_access(rqp->sr_share, scred, SMBM_EXEC);
99                 if (error)
100                         return error;
101         }
102         rqp->sr_cred = scred;
103         rqp->sr_mid = smb_vc_nextmid(rqp->sr_vc);
104         return smb_rq_new(rqp, cmd);
105 }
106
107 static int
108 smb_rq_new(struct smb_rq *rqp, u_char cmd)
109 {
110         struct smb_vc *vcp = rqp->sr_vc;
111         struct mbchain *mbp = &rqp->sr_rq;
112         int error;
113
114         rqp->sr_sendcnt = 0;
115         mb_done(mbp);
116         md_done(&rqp->sr_rp);
117         error = mb_init(mbp);
118         if (error)
119                 return error;
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);
130         return 0;
131 }
132
133 void
134 smb_rq_done(struct smb_rq *rqp)
135 {
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)
140                 kfree(rqp, M_SMBRQ);
141 }
142
143 /*
144  * Simple request-reply exchange
145  */
146 int
147 smb_rq_simple(struct smb_rq *rqp)
148 {
149         struct smb_vc *vcp = rqp->sr_vc;
150         int error = EINVAL, i;
151
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);
157                 if (error)
158                         return error;
159                 error = smb_rq_reply(rqp);
160                 if (error == 0)
161                         break;
162                 if ((rqp->sr_flags & (SMBR_RESTART | SMBR_NORESTART)) != SMBR_RESTART)
163                         break;
164         }
165         return error;
166 }
167
168 static int
169 smb_rq_enqueue(struct smb_rq *rqp)
170 {
171         struct smb_share *ssp = rqp->sr_share;
172         int error;
173
174         if (ssp == NULL || rqp->sr_cred == &rqp->sr_vc->vc_iod->iod_scred) {
175                 return smb_iod_addrq(rqp);
176         }
177         for (;;) {
178                 SMBS_ST_LOCK(ssp);
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))
183                                 return EINTR;
184                         continue;
185                 }
186                 if (smb_share_valid(ssp) || (ssp->ss_flags & SMBS_CONNECTED) == 0) {
187                         SMBS_ST_UNLOCK(ssp);
188                 } else {
189                         SMBS_ST_UNLOCK(ssp);
190                         error = smb_iod_request(rqp->sr_vc->vc_iod,
191                             SMBIOD_EV_TREECONNECT | SMBIOD_EV_SYNC, ssp);
192                         if (error)
193                                 return error;
194                 }
195                 error = smb_iod_addrq(rqp);
196                 if (error != EXDEV)
197                         break;
198         }
199         return error;
200 }
201
202 void
203 smb_rq_wstart(struct smb_rq *rqp)
204 {
205         rqp->sr_wcount = mb_reserve(&rqp->sr_rq, sizeof(u_int8_t));
206         rqp->sr_rq.mb_count = 0;
207 }
208
209 void
210 smb_rq_wend(struct smb_rq *rqp)
211 {
212         if (rqp->sr_wcount == NULL) {
213                 SMBERROR("no wcount\n");        /* actually panic */
214                 return;
215         }
216         if (rqp->sr_rq.mb_count & 1)
217                 SMBERROR("odd word count\n");
218         *rqp->sr_wcount = rqp->sr_rq.mb_count / 2;
219 }
220
221 void
222 smb_rq_bstart(struct smb_rq *rqp)
223 {
224         rqp->sr_bcount = (u_short*)mb_reserve(&rqp->sr_rq, sizeof(u_short));
225         rqp->sr_rq.mb_count = 0;
226 }
227
228 void
229 smb_rq_bend(struct smb_rq *rqp)
230 {
231         int bcnt;
232
233         if (rqp->sr_bcount == NULL) {
234                 SMBERROR("no bcount\n");        /* actually panic */
235                 return;
236         }
237         bcnt = rqp->sr_rq.mb_count;
238         if (bcnt > 0xffff)
239                 SMBERROR("byte count too large (%d)\n", bcnt);
240         *rqp->sr_bcount = bcnt;
241 }
242
243 int
244 smb_rq_intr(struct smb_rq *rqp)
245 {
246         struct thread *td = rqp->sr_cred->scr_td;
247
248         if (rqp->sr_flags & SMBR_INTR)
249                 return EINTR;
250         return smb_proc_intr(td);
251 }
252
253 int
254 smb_rq_getrequest(struct smb_rq *rqp, struct mbchain **mbpp)
255 {
256         *mbpp = &rqp->sr_rq;
257         return 0;
258 }
259
260 int
261 smb_rq_getreply(struct smb_rq *rqp, struct mdchain **mbpp)
262 {
263         *mbpp = &rqp->sr_rp;
264         return 0;
265 }
266
267 static int
268 smb_rq_getenv(struct smb_connobj *layer,
269         struct smb_vc **vcpp, struct smb_share **sspp)
270 {
271         struct smb_vc *vcp = NULL;
272         struct smb_share *ssp = NULL;
273         struct smb_connobj *cp;
274         int error = 0;
275
276         switch (layer->co_level) {
277             case SMBL_VC:
278                 vcp = CPTOVC(layer);
279                 if (layer->co_parent == NULL) {
280                         SMBERROR("zombie VC %s\n", vcp->vc_srvname);
281                         error = EINVAL;
282                         break;
283                 }
284                 break;
285             case SMBL_SHARE:
286                 ssp = CPTOSS(layer);
287                 cp = layer->co_parent;
288                 if (cp == NULL) {
289                         SMBERROR("zombie share %s\n", ssp->ss_name);
290                         error = EINVAL;
291                         break;
292                 }
293                 error = smb_rq_getenv(cp, &vcp, NULL);
294                 if (error)
295                         break;
296                 break;
297             default:
298                 SMBERROR("invalid layer %d passed\n", layer->co_level);
299                 error = EINVAL;
300         }
301         if (vcpp)
302                 *vcpp = vcp;
303         if (sspp)
304                 *sspp = ssp;
305         return error;
306 }
307
308 /*
309  * Wait for reply on the request
310  */
311 static int
312 smb_rq_reply(struct smb_rq *rqp)
313 {
314         struct mdchain *mdp = &rqp->sr_rp;
315         u_int32_t tdw;
316         u_int8_t tb;
317         int error, rperror = 0;
318
319         error = smb_iod_waitrq(rqp);
320         if (error)
321                 return error;
322         error = md_get_uint32(mdp, &tdw);
323         if (error)
324                 return error;
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);
328         } else {
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);
332                 if (!error)
333                         rperror = smb_maperror(rqp->sr_errclass, rqp->sr_serror);
334         }
335         error = md_get_uint8(mdp, &rqp->sr_rpflags);
336         error = md_get_uint16le(mdp, &rqp->sr_rpflags2);
337
338         error = md_get_uint32(mdp, &tdw);
339         error = md_get_uint32(mdp, &tdw);
340         error = md_get_uint32(mdp, &tdw);
341
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);
346
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;
351 }
352
353
354 #define ALIGN4(a)       (((a) + 3) & ~3)
355
356 /*
357  * TRANS2 request implementation
358  */
359 int
360 smb_t2_alloc(struct smb_connobj *layer, u_short setup, struct smb_cred *scred,
361         struct smb_t2rq **t2pp)
362 {
363         struct smb_t2rq *t2p;
364         int error;
365
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;
369         if (error) {
370                 smb_t2_done(t2p);
371                 return error;
372         }
373         *t2pp = t2p;
374         return 0;
375 }
376
377 int
378 smb_t2_init(struct smb_t2rq *t2p, struct smb_connobj *source, u_short setup,
379         struct smb_cred *scred)
380 {
381         int error;
382
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);
391         if (error)
392                 return error;
393         return 0;
394 }
395
396 void
397 smb_t2_done(struct smb_t2rq *t2p)
398 {
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)
404                 kfree(t2p, M_SMBRQ);
405 }
406
407 static int
408 smb_t2_placedata(struct mbuf *mtop, u_int16_t offset, u_int16_t count,
409         struct mdchain *mdp)
410 {
411         struct mbuf *m, *m0;
412         int len;
413
414         m0 = m_split(mtop, offset, MB_WAIT);
415         if (m0 == NULL)
416                 return EBADRPC;
417         for(len = 0, m = m0; m->m_next; m = m->m_next)
418                 len += m->m_len;
419         len += m->m_len;
420         m->m_len -= len - count;
421         if (mdp->md_top == NULL) {
422                 md_initm(mdp, m0);
423         } else
424                 m_cat(mdp->md_top, m0);
425         return 0;
426 }
427
428 static int
429 smb_t2_reply(struct smb_t2rq *t2p)
430 {
431         struct mdchain *mdp;
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;
436         u_int8_t wc;
437
438         error = smb_rq_reply(rqp);
439         if (error)
440                 return error;
441         if ((t2p->t2_flags & SMBT2_ALLSENT) == 0) {
442                 /* 
443                  * this is an interim response, ignore it.
444                  */
445                 SMBRQ_SLOCK(rqp);
446                 md_next_record(&rqp->sr_rp);
447                 SMBRQ_SUNLOCK(rqp);
448                 return 0;
449         }
450         /*
451          * Now we have to get all subsequent responses. The CIFS specification
452          * says that they can be disordered which is weird.
453          * TODO: timo
454          */
455         totpgot = totdgot = 0;
456         totpcount = totdcount = 0xffff;
457         mdp = &rqp->sr_rp;
458         for (;;) {
459                 m_dumpm(mdp->md_top);
460                 if ((error = md_get_uint8(mdp, &wc)) != 0)
461                         break;
462                 if (wc < 10) {
463                         error = ENOENT;
464                         break;
465                 }
466                 if ((error = md_get_uint16le(mdp, &tmp)) != 0)
467                         break;
468                 if (totpcount > tmp)
469                         totpcount = tmp;
470                 md_get_uint16le(mdp, &tmp);
471                 if (totdcount > tmp)
472                         totdcount = 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)
477                         break;
478                 if (pcount != 0 && pdisp != totpgot) {
479                         SMBERROR("Can't handle disordered parameters %d:%d\n",
480                             pdisp, totpgot);
481                         error = EINVAL;
482                         break;
483                 }
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)
487                         break;
488                 if (dcount != 0 && ddisp != totdgot) {
489                         SMBERROR("Can't handle disordered data\n");
490                         error = EINVAL;
491                         break;
492                 }
493                 md_get_uint8(mdp, &wc);
494                 md_get_uint8(mdp, NULL);
495                 tmp = wc;
496                 while (tmp--)
497                         md_get_uint16(mdp, NULL);
498                 if ((error = md_get_uint16le(mdp, &bc)) != 0)
499                         break;
500 /*              tmp = SMB_HDRLEN + 1 + 10 * 2 + 2 * wc + 2;*/
501                 if (dcount) {
502                         error = smb_t2_placedata(mdp->md_top, doff, dcount,
503                             &t2p->t2_rdata);
504                         if (error)
505                                 break;
506                 }
507                 if (pcount) {
508                         error = smb_t2_placedata(mdp->md_top, poff, pcount,
509                             &t2p->t2_rparam);
510                         if (error)
511                                 break;
512                 }
513                 totpgot += pcount;
514                 totdgot += dcount;
515                 if (totpgot >= totpcount && totdgot >= totdcount) {
516                         error = 0;
517                         t2p->t2_flags |= SMBT2_ALLRECV;
518                         break;
519                 }
520                 /*
521                  * We're done with this reply, look for the next one.
522                  */
523                 SMBRQ_SLOCK(rqp);
524                 md_next_record(&rqp->sr_rp);
525                 SMBRQ_SUNLOCK(rqp);
526                 error = smb_rq_reply(rqp);
527                 if (error)
528                         break;
529         }
530         return error;
531 }
532
533 /*
534  * Perform a full round of TRANS2 request
535  */
536 static int
537 smb_t2_request_int(struct smb_t2rq *t2p)
538 {
539         struct smb_vc *vcp = t2p->t2_vc;
540         struct smb_cred *scred = t2p->t2_cred;
541         struct mbchain *mbp;
542         struct mdchain *mdp, mbparam, mbdata;
543         struct mbuf *m;
544         struct smb_rq *rqp;
545         int totpcount, leftpcount, totdcount, leftdcount, len, txmax, i;
546         int error, doff, poff, txdcount, txpcount, nmlen;
547
548         m = t2p->t2_tparam.mb_top;
549         if (m) {
550                 md_initm(&mbparam, m);  /* do not free it! */
551                 totpcount = m_fixhdr(m);
552                 if (totpcount > 0xffff)         /* maxvalue for u_short */
553                         return EINVAL;
554         } else
555                 totpcount = 0;
556         m = t2p->t2_tdata.mb_top;
557         if (m) {
558                 md_initm(&mbdata, m);   /* do not free it! */
559                 totdcount =  m_fixhdr(m);
560                 if (totdcount > 0xffff)
561                         return EINVAL;
562         } else
563                 totdcount = 0;
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);
569         if (error)
570                 return error;
571         rqp->sr_flags |= SMBR_MULTIPACKET;
572         t2p->t2_rq = rqp;
573         mbp = &rqp->sr_rq;
574         smb_rq_wstart(rqp);
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);
585         /*
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
589          */
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);
594                 poff = len;
595                 txdcount = 0;
596                 doff = 0;
597         } else {
598                 txpcount = leftpcount;
599                 poff = txpcount ? len : 0;
600                 len = ALIGN4(len + txpcount);
601                 txdcount = min(leftdcount, txmax - len);
602                 doff = txdcount ? len : 0;
603         }
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]);
614         smb_rq_wend(rqp);
615         smb_rq_bstart(rqp);
616         /* TDUNICODE */
617         if (t2p->t_name)
618                 mb_put_mem(mbp, t2p->t_name, nmlen, MB_MSYSTEM);
619         mb_put_uint8(mbp, 0);   /* terminating zero */
620         len = mb_fixhdr(mbp);
621         if (txpcount) {
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);
625                 if (error)
626                         goto freerq;
627                 mb_put_mbuf(mbp, m);
628         }
629         len = mb_fixhdr(mbp);
630         if (txdcount) {
631                 mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
632                 error = md_get_mbuf(&mbdata, txdcount, &m);
633                 if (error)
634                         goto freerq;
635                 mb_put_mbuf(mbp, m);
636         }
637         smb_rq_bend(rqp);       /* incredible, but thats it... */
638         error = smb_rq_enqueue(rqp);
639         if (error)
640                 goto freerq;
641         if (leftpcount == 0 && leftdcount == 0)
642                 t2p->t2_flags |= SMBT2_ALLSENT;
643         error = smb_t2_reply(t2p);
644         if (error)
645                 goto bad;
646         while (leftpcount || leftdcount) {
647                 error = smb_rq_new(rqp, t2p->t_name ? 
648                     SMB_COM_TRANSACTION_SECONDARY : SMB_COM_TRANSACTION2_SECONDARY);
649                 if (error)
650                         goto bad;
651                 mbp = &rqp->sr_rq;
652                 smb_rq_wstart(rqp);
653                 mb_put_uint16le(mbp, totpcount);
654                 mb_put_uint16le(mbp, totdcount);
655                 len = mb_fixhdr(mbp);
656                 /*
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
660                  */
661                 len = ALIGN4(len + 6 * 2 + 2);
662                 if (t2p->t_name == NULL)
663                         len += 2;
664                 if (len + leftpcount > txmax) {
665                         txpcount = min(leftpcount, txmax - len);
666                         poff = len;
667                         txdcount = 0;
668                         doff = 0;
669                 } else {
670                         txpcount = leftpcount;
671                         poff = txpcount ? len : 0;
672                         len = ALIGN4(len + txpcount);
673                         txdcount = min(leftdcount, txmax - len);
674                         doff = txdcount ? len : 0;
675                 }
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);
686                 smb_rq_wend(rqp);
687                 smb_rq_bstart(rqp);
688                 mb_put_uint8(mbp, 0);   /* name */
689                 len = mb_fixhdr(mbp);
690                 if (txpcount) {
691                         mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
692                         error = md_get_mbuf(&mbparam, txpcount, &m);
693                         if (error)
694                                 goto bad;
695                         mb_put_mbuf(mbp, m);
696                 }
697                 len = mb_fixhdr(mbp);
698                 if (txdcount) {
699                         mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO);
700                         error = md_get_mbuf(&mbdata, txdcount, &m);
701                         if (error)
702                                 goto bad;
703                         mb_put_mbuf(mbp, m);
704                 }
705                 smb_rq_bend(rqp);
706                 rqp->sr_state = SMBRQ_NOTSENT;
707                 error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_NEWRQ, NULL);
708                 if (error)
709                         goto bad;
710         }       /* while left params or data */
711         t2p->t2_flags |= SMBT2_ALLSENT;
712         mdp = &t2p->t2_rdata;
713         if (mdp->md_top) {
714                 m_fixhdr(mdp->md_top);
715                 md_initm(mdp, mdp->md_top);
716         }
717         mdp = &t2p->t2_rparam;
718         if (mdp->md_top) {
719                 m_fixhdr(mdp->md_top);
720                 md_initm(mdp, mdp->md_top);
721         }
722 bad:
723         smb_iod_removerq(rqp);
724 freerq:
725         smb_rq_done(rqp);
726         if (error) {
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);
731         }
732         return error;
733 }
734
735 int
736 smb_t2_request(struct smb_t2rq *t2p)
737 {
738         int error = EINVAL, i;
739
740         for (i = 0; i < SMB_MAXRCN; i++) {
741                 t2p->t2_flags &= ~SMBR_RESTART;
742                 error = smb_t2_request_int(t2p);
743                 if (error == 0)
744                         break;
745                 if ((t2p->t2_flags & (SMBT2_RESTART | SMBT2_NORESTART)) != SMBT2_RESTART)
746                         break;
747         }
748         return error;
749 }