]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/netsmb/smb_iod.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / netsmb / smb_iod.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
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35  
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/endian.h>
39 #include <sys/proc.h>
40 #include <sys/kernel.h>
41 #include <sys/kthread.h>
42 #include <sys/malloc.h>
43 #include <sys/mbuf.h>
44 #include <sys/unistd.h>
45
46 #include <netsmb/smb.h>
47 #include <netsmb/smb_conn.h>
48 #include <netsmb/smb_rq.h>
49 #include <netsmb/smb_tran.h>
50 #include <netsmb/smb_trantcp.h>
51
52
53 #define SMBIOD_SLEEP_TIMO       2
54 #define SMBIOD_PING_TIMO        60      /* seconds */
55
56 #define SMB_IOD_EVLOCKPTR(iod)  (&((iod)->iod_evlock))
57 #define SMB_IOD_EVLOCK(iod)     smb_sl_lock(&((iod)->iod_evlock))
58 #define SMB_IOD_EVUNLOCK(iod)   smb_sl_unlock(&((iod)->iod_evlock))
59
60 #define SMB_IOD_RQLOCKPTR(iod)  (&((iod)->iod_rqlock))
61 #define SMB_IOD_RQLOCK(iod)     smb_sl_lock(&((iod)->iod_rqlock))
62 #define SMB_IOD_RQUNLOCK(iod)   smb_sl_unlock(&((iod)->iod_rqlock))
63
64 #define smb_iod_wakeup(iod)     wakeup(&(iod)->iod_flags)
65
66
67 static MALLOC_DEFINE(M_SMBIOD, "SMBIOD", "SMB network io daemon");
68
69 static int smb_iod_next;
70
71 static int  smb_iod_sendall(struct smbiod *iod);
72 static int  smb_iod_disconnect(struct smbiod *iod);
73 static void smb_iod_thread(void *);
74
75 static __inline void
76 smb_iod_rqprocessed(struct smb_rq *rqp, int error)
77 {
78         SMBRQ_SLOCK(rqp);
79         rqp->sr_lerror = error;
80         rqp->sr_rpgen++;
81         rqp->sr_state = SMBRQ_NOTIFIED;
82         wakeup(&rqp->sr_state);
83         SMBRQ_SUNLOCK(rqp);
84 }
85
86 static void
87 smb_iod_invrq(struct smbiod *iod)
88 {
89         struct smb_rq *rqp;
90
91         /*
92          * Invalidate all outstanding requests for this connection
93          */
94         SMB_IOD_RQLOCK(iod);
95         TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
96                 if (rqp->sr_flags & SMBR_INTERNAL)
97                         SMBRQ_SUNLOCK(rqp);
98                 rqp->sr_flags |= SMBR_RESTART;
99                 smb_iod_rqprocessed(rqp, ENOTCONN);
100         }
101         SMB_IOD_RQUNLOCK(iod);
102 }
103
104 static void
105 smb_iod_closetran(struct smbiod *iod)
106 {
107         struct smb_vc *vcp = iod->iod_vc;
108         struct thread *td = iod->iod_td;
109
110         if (vcp->vc_tdata == NULL)
111                 return;
112         SMB_TRAN_DISCONNECT(vcp, td);
113         SMB_TRAN_DONE(vcp, td);
114         vcp->vc_tdata = NULL;
115 }
116
117 static void
118 smb_iod_dead(struct smbiod *iod)
119 {
120         iod->iod_state = SMBIOD_ST_DEAD;
121         smb_iod_closetran(iod);
122         smb_iod_invrq(iod);
123 }
124
125 static int
126 smb_iod_connect(struct smbiod *iod)
127 {
128         struct smb_vc *vcp = iod->iod_vc;
129         struct thread *td = iod->iod_td;
130         int error;
131
132         SMBIODEBUG("%d\n", iod->iod_state);
133         switch(iod->iod_state) {
134             case SMBIOD_ST_VCACTIVE:
135                 SMBERROR("called for already opened connection\n");
136                 return EISCONN;
137             case SMBIOD_ST_DEAD:
138                 return ENOTCONN;        /* XXX: last error code ? */
139             default:
140                 break;
141         }
142         vcp->vc_genid++;
143         error = 0;
144
145         error = (int)SMB_TRAN_CREATE(vcp, td);
146         if (error)
147                 goto fail;
148         SMBIODEBUG("tcreate\n");
149         if (vcp->vc_laddr) {
150                 error = (int)SMB_TRAN_BIND(vcp, vcp->vc_laddr, td);
151                 if (error)
152                         goto fail;
153         }
154         SMBIODEBUG("tbind\n");
155         error = (int)SMB_TRAN_CONNECT(vcp, vcp->vc_paddr, td);
156         if (error)
157                 goto fail;
158         SMB_TRAN_SETPARAM(vcp, SMBTP_SELECTID, &iod->iod_flags);
159         iod->iod_state = SMBIOD_ST_TRANACTIVE;
160         SMBIODEBUG("tconnect\n");
161         /* vcp->vc_mid = 0;*/
162         error = (int)smb_smb_negotiate(vcp, &iod->iod_scred);
163         if (error)
164                 goto fail;
165         SMBIODEBUG("snegotiate\n");
166         error = (int)smb_smb_ssnsetup(vcp, &iod->iod_scred);
167         if (error)
168                 goto fail;
169         iod->iod_state = SMBIOD_ST_VCACTIVE;
170         SMBIODEBUG("completed\n");
171         smb_iod_invrq(iod);
172         return (0);
173
174  fail:
175         smb_iod_dead(iod);
176         return (error);
177 }
178
179 static int
180 smb_iod_disconnect(struct smbiod *iod)
181 {
182         struct smb_vc *vcp = iod->iod_vc;
183
184         SMBIODEBUG("\n");
185         if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
186                 smb_smb_ssnclose(vcp, &iod->iod_scred);
187                 iod->iod_state = SMBIOD_ST_TRANACTIVE;
188         }
189         vcp->vc_smbuid = SMB_UID_UNKNOWN;
190         smb_iod_closetran(iod);
191         iod->iod_state = SMBIOD_ST_NOTCONN;
192         return 0;
193 }
194
195 static int
196 smb_iod_treeconnect(struct smbiod *iod, struct smb_share *ssp)
197 {
198         int error;
199
200         if (iod->iod_state != SMBIOD_ST_VCACTIVE) {
201                 if (iod->iod_state != SMBIOD_ST_DEAD)
202                         return ENOTCONN;
203                 iod->iod_state = SMBIOD_ST_RECONNECT;
204                 error = smb_iod_connect(iod);
205                 if (error)
206                         return error;
207         }
208         SMBIODEBUG("tree reconnect\n");
209         SMBS_ST_LOCK(ssp);
210         ssp->ss_flags |= SMBS_RECONNECTING;
211         SMBS_ST_UNLOCK(ssp);
212         error = smb_smb_treeconnect(ssp, &iod->iod_scred);
213         SMBS_ST_LOCK(ssp);
214         ssp->ss_flags &= ~SMBS_RECONNECTING;
215         SMBS_ST_UNLOCK(ssp);
216         wakeup(&ssp->ss_vcgenid);
217         return error;
218 }
219
220 static int
221 smb_iod_sendrq(struct smbiod *iod, struct smb_rq *rqp)
222 {
223         struct thread *td = iod->iod_td;
224         struct smb_vc *vcp = iod->iod_vc;
225         struct smb_share *ssp = rqp->sr_share;
226         struct mbuf *m;
227         int error;
228
229         SMBIODEBUG("iod_state = %d\n", iod->iod_state);
230         switch (iod->iod_state) {
231             case SMBIOD_ST_NOTCONN:
232                 smb_iod_rqprocessed(rqp, ENOTCONN);
233                 return 0;
234             case SMBIOD_ST_DEAD:
235                 iod->iod_state = SMBIOD_ST_RECONNECT;
236                 return 0;
237             case SMBIOD_ST_RECONNECT:
238                 return 0;
239             default:
240                 break;
241         }
242         if (rqp->sr_sendcnt == 0) {
243 #ifdef movedtoanotherplace
244                 if (vcp->vc_maxmux != 0 && iod->iod_muxcnt >= vcp->vc_maxmux)
245                         return 0;
246 #endif
247                 le16enc(rqp->sr_rqtid, ssp ? ssp->ss_tid : SMB_TID_UNKNOWN);
248                 le16enc(rqp->sr_rquid, vcp ? vcp->vc_smbuid : 0);
249                 mb_fixhdr(&rqp->sr_rq);
250                 if (vcp->vc_hflags2 & SMB_FLAGS2_SECURITY_SIGNATURE)
251                         smb_rq_sign(rqp);
252         }
253         if (rqp->sr_sendcnt++ > 5) {
254                 rqp->sr_flags |= SMBR_RESTART;
255                 smb_iod_rqprocessed(rqp, rqp->sr_lerror);
256                 /*
257                  * If all attempts to send a request failed, then
258                  * something is seriously hosed.
259                  */
260                 return ENOTCONN;
261         }
262         SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x\n", rqp->sr_mid, 0, 0, 0);
263         m_dumpm(rqp->sr_rq.mb_top);
264         m = m_copym(rqp->sr_rq.mb_top, 0, M_COPYALL, M_WAIT);
265         error = rqp->sr_lerror = SMB_TRAN_SEND(vcp, m, td);
266         if (error == 0) {
267                 getnanotime(&rqp->sr_timesent);
268                 iod->iod_lastrqsent = rqp->sr_timesent;
269                 rqp->sr_flags |= SMBR_SENT;
270                 rqp->sr_state = SMBRQ_SENT;
271                 return 0;
272         }
273         /*
274          * Check for fatal errors
275          */
276         if (SMB_TRAN_FATAL(vcp, error)) {
277                 /*
278                  * No further attempts should be made
279                  */
280                 return ENOTCONN;
281         }
282         if (smb_rq_intr(rqp))
283                 smb_iod_rqprocessed(rqp, EINTR);
284         return 0;
285 }
286
287 /*
288  * Process incoming packets
289  */
290 static int
291 smb_iod_recvall(struct smbiod *iod)
292 {
293         struct smb_vc *vcp = iod->iod_vc;
294         struct thread *td = iod->iod_td;
295         struct smb_rq *rqp;
296         struct mbuf *m;
297         u_char *hp;
298         u_short mid;
299         int error;
300
301         switch (iod->iod_state) {
302             case SMBIOD_ST_NOTCONN:
303             case SMBIOD_ST_DEAD:
304             case SMBIOD_ST_RECONNECT:
305                 return 0;
306             default:
307                 break;
308         }
309         for (;;) {
310                 m = NULL;
311                 error = SMB_TRAN_RECV(vcp, &m, td);
312                 if (error == EWOULDBLOCK)
313                         break;
314                 if (SMB_TRAN_FATAL(vcp, error)) {
315                         smb_iod_dead(iod);
316                         break;
317                 }
318                 if (error)
319                         break;
320                 if (m == NULL) {
321                         SMBERROR("tran return NULL without error\n");
322                         error = EPIPE;
323                         continue;
324                 }
325                 m = m_pullup(m, SMB_HDRLEN);
326                 if (m == NULL)
327                         continue;       /* wait for a good packet */
328                 /*
329                  * Now we got an entire and possibly invalid SMB packet.
330                  * Be careful while parsing it.
331                  */
332                 m_dumpm(m);
333                 hp = mtod(m, u_char*);
334                 if (bcmp(hp, SMB_SIGNATURE, SMB_SIGLEN) != 0) {
335                         m_freem(m);
336                         continue;
337                 }
338                 mid = SMB_HDRMID(hp);
339                 SMBSDEBUG("mid %04x\n", (u_int)mid);
340                 SMB_IOD_RQLOCK(iod);
341                 TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
342                         if (rqp->sr_mid != mid)
343                                 continue;
344                         SMBRQ_SLOCK(rqp);
345                         if (rqp->sr_rp.md_top == NULL) {
346                                 md_initm(&rqp->sr_rp, m);
347                         } else {
348                                 if (rqp->sr_flags & SMBR_MULTIPACKET) {
349                                         md_append_record(&rqp->sr_rp, m);
350                                 } else {
351                                         SMBRQ_SUNLOCK(rqp);
352                                         SMBERROR("duplicate response %d (ignored)\n", mid);
353                                         break;
354                                 }
355                         }
356                         SMBRQ_SUNLOCK(rqp);
357                         smb_iod_rqprocessed(rqp, 0);
358                         break;
359                 }
360                 SMB_IOD_RQUNLOCK(iod);
361                 if (rqp == NULL) {
362                         SMBERROR("drop resp with mid %d\n", (u_int)mid);
363 /*                      smb_printrqlist(vcp);*/
364                         m_freem(m);
365                 }
366         }
367         /*
368          * check for interrupts
369          */
370         SMB_IOD_RQLOCK(iod);
371         TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
372                 if (smb_td_intr(rqp->sr_cred->scr_td)) {
373                         smb_iod_rqprocessed(rqp, EINTR);
374                 }
375         }
376         SMB_IOD_RQUNLOCK(iod);
377         return 0;
378 }
379
380 int
381 smb_iod_request(struct smbiod *iod, int event, void *ident)
382 {
383         struct smbiod_event *evp;
384         int error;
385
386         SMBIODEBUG("\n");
387         evp = smb_zmalloc(sizeof(*evp), M_SMBIOD, M_WAITOK);
388         evp->ev_type = event;
389         evp->ev_ident = ident;
390         SMB_IOD_EVLOCK(iod);
391         STAILQ_INSERT_TAIL(&iod->iod_evlist, evp, ev_link);
392         if ((event & SMBIOD_EV_SYNC) == 0) {
393                 SMB_IOD_EVUNLOCK(iod);
394                 smb_iod_wakeup(iod);
395                 return 0;
396         }
397         smb_iod_wakeup(iod);
398         msleep(evp, SMB_IOD_EVLOCKPTR(iod), PWAIT | PDROP, "90evw", 0);
399         error = evp->ev_error;
400         free(evp, M_SMBIOD);
401         return error;
402 }
403
404 /*
405  * Place request in the queue.
406  * Request from smbiod have a high priority.
407  */
408 int
409 smb_iod_addrq(struct smb_rq *rqp)
410 {
411         struct smb_vc *vcp = rqp->sr_vc;
412         struct smbiod *iod = vcp->vc_iod;
413         int error;
414
415         SMBIODEBUG("\n");
416         if (rqp->sr_cred->scr_td != NULL &&
417             rqp->sr_cred->scr_td->td_proc == iod->iod_p) {
418                 rqp->sr_flags |= SMBR_INTERNAL;
419                 SMB_IOD_RQLOCK(iod);
420                 TAILQ_INSERT_HEAD(&iod->iod_rqlist, rqp, sr_link);
421                 SMB_IOD_RQUNLOCK(iod);
422                 for (;;) {
423                         if (smb_iod_sendrq(iod, rqp) != 0) {
424                                 smb_iod_dead(iod);
425                                 break;
426                         }
427                         /*
428                          * we don't need to lock state field here
429                          */
430                         if (rqp->sr_state != SMBRQ_NOTSENT)
431                                 break;
432                         tsleep(&iod->iod_flags, PWAIT, "90sndw", hz);
433                 }
434                 if (rqp->sr_lerror)
435                         smb_iod_removerq(rqp);
436                 return rqp->sr_lerror;
437         }
438
439         switch (iod->iod_state) {
440             case SMBIOD_ST_NOTCONN:
441                 return ENOTCONN;
442             case SMBIOD_ST_DEAD:
443                 error = smb_iod_request(vcp->vc_iod, SMBIOD_EV_CONNECT | SMBIOD_EV_SYNC, NULL);
444                 if (error)
445                         return error;
446                 return EXDEV;
447             default:
448                 break;
449         }
450
451         SMB_IOD_RQLOCK(iod);
452         for (;;) {
453                 if (vcp->vc_maxmux == 0) {
454                         SMBERROR("maxmux == 0\n");
455                         break;
456                 }
457                 if (iod->iod_muxcnt < vcp->vc_maxmux)
458                         break;
459                 iod->iod_muxwant++;
460                 msleep(&iod->iod_muxwant, SMB_IOD_RQLOCKPTR(iod),
461                     PWAIT, "90mux", 0);
462         }
463         iod->iod_muxcnt++;
464         TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
465         SMB_IOD_RQUNLOCK(iod);
466         smb_iod_wakeup(iod);
467         return 0;
468 }
469
470 int
471 smb_iod_removerq(struct smb_rq *rqp)
472 {
473         struct smb_vc *vcp = rqp->sr_vc;
474         struct smbiod *iod = vcp->vc_iod;
475
476         SMBIODEBUG("\n");
477         if (rqp->sr_flags & SMBR_INTERNAL) {
478                 SMB_IOD_RQLOCK(iod);
479                 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
480                 SMB_IOD_RQUNLOCK(iod);
481                 return 0;
482         }
483         SMB_IOD_RQLOCK(iod);
484         while (rqp->sr_flags & SMBR_XLOCK) {
485                 rqp->sr_flags |= SMBR_XLOCKWANT;
486                 msleep(rqp, SMB_IOD_RQLOCKPTR(iod), PWAIT, "90xrm", 0);
487         }
488         TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
489         iod->iod_muxcnt--;
490         if (iod->iod_muxwant) {
491                 iod->iod_muxwant--;
492                 wakeup(&iod->iod_muxwant);
493         }
494         SMB_IOD_RQUNLOCK(iod);
495         return 0;
496 }
497
498 int
499 smb_iod_waitrq(struct smb_rq *rqp)
500 {
501         struct smbiod *iod = rqp->sr_vc->vc_iod;
502         int error;
503
504         SMBIODEBUG("\n");
505         if (rqp->sr_flags & SMBR_INTERNAL) {
506                 for (;;) {
507                         smb_iod_sendall(iod);
508                         smb_iod_recvall(iod);
509                         if (rqp->sr_rpgen != rqp->sr_rplast)
510                                 break;
511                         tsleep(&iod->iod_flags, PWAIT, "90irq", hz);
512                 }
513                 smb_iod_removerq(rqp);
514                 return rqp->sr_lerror;
515
516         }
517         SMBRQ_SLOCK(rqp);
518         if (rqp->sr_rpgen == rqp->sr_rplast)
519                 msleep(&rqp->sr_state, SMBRQ_SLOCKPTR(rqp), PWAIT, "90wrq", 0);
520         rqp->sr_rplast++;
521         SMBRQ_SUNLOCK(rqp);
522         error = rqp->sr_lerror;
523         if (rqp->sr_flags & SMBR_MULTIPACKET) {
524                 /*
525                  * If request should stay in the list, then reinsert it
526                  * at the end of queue so other waiters have chance to concur
527                  */
528                 SMB_IOD_RQLOCK(iod);
529                 TAILQ_REMOVE(&iod->iod_rqlist, rqp, sr_link);
530                 TAILQ_INSERT_TAIL(&iod->iod_rqlist, rqp, sr_link);
531                 SMB_IOD_RQUNLOCK(iod);
532         } else
533                 smb_iod_removerq(rqp);
534         return error;
535 }
536
537
538 static int
539 smb_iod_sendall(struct smbiod *iod)
540 {
541         struct smb_vc *vcp = iod->iod_vc;
542         struct smb_rq *rqp;
543         struct timespec ts, tstimeout;
544         int herror;
545
546         herror = 0;
547         /*
548          * Loop through the list of requests and send them if possible
549          */
550         SMB_IOD_RQLOCK(iod);
551         TAILQ_FOREACH(rqp, &iod->iod_rqlist, sr_link) {
552                 switch (rqp->sr_state) {
553                     case SMBRQ_NOTSENT:
554                         rqp->sr_flags |= SMBR_XLOCK;
555                         SMB_IOD_RQUNLOCK(iod);
556                         herror = smb_iod_sendrq(iod, rqp);
557                         SMB_IOD_RQLOCK(iod);
558                         rqp->sr_flags &= ~SMBR_XLOCK;
559                         if (rqp->sr_flags & SMBR_XLOCKWANT) {
560                                 rqp->sr_flags &= ~SMBR_XLOCKWANT;
561                                 wakeup(rqp);
562                         }
563                         break;
564                     case SMBRQ_SENT:
565                         SMB_TRAN_GETPARAM(vcp, SMBTP_TIMEOUT, &tstimeout);
566                         timespecadd(&tstimeout, &tstimeout);
567                         getnanotime(&ts);
568                         timespecsub(&ts, &tstimeout);
569                         if (timespeccmp(&ts, &rqp->sr_timesent, >)) {
570                                 smb_iod_rqprocessed(rqp, ETIMEDOUT);
571                         }
572                         break;
573                     default:
574                         break;
575                 }
576                 if (herror)
577                         break;
578         }
579         SMB_IOD_RQUNLOCK(iod);
580         if (herror == ENOTCONN)
581                 smb_iod_dead(iod);
582         return 0;
583 }
584
585 /*
586  * "main" function for smbiod daemon
587  */
588 static __inline void
589 smb_iod_main(struct smbiod *iod)
590 {
591 /*      struct smb_vc *vcp = iod->iod_vc;*/
592         struct smbiod_event *evp;
593 /*      struct timespec tsnow;*/
594         int error;
595
596         SMBIODEBUG("\n");
597         error = 0;
598
599         /*
600          * Check all interesting events
601          */
602         for (;;) {
603                 SMB_IOD_EVLOCK(iod);
604                 evp = STAILQ_FIRST(&iod->iod_evlist);
605                 if (evp == NULL) {
606                         SMB_IOD_EVUNLOCK(iod);
607                         break;
608                 }
609                 STAILQ_REMOVE_HEAD(&iod->iod_evlist, ev_link);
610                 evp->ev_type |= SMBIOD_EV_PROCESSING;
611                 SMB_IOD_EVUNLOCK(iod);
612                 switch (evp->ev_type & SMBIOD_EV_MASK) {
613                     case SMBIOD_EV_CONNECT:
614                         iod->iod_state = SMBIOD_ST_RECONNECT;
615                         evp->ev_error = smb_iod_connect(iod);
616                         break;
617                     case SMBIOD_EV_DISCONNECT:
618                         evp->ev_error = smb_iod_disconnect(iod);
619                         break;
620                     case SMBIOD_EV_TREECONNECT:
621                         evp->ev_error = smb_iod_treeconnect(iod, evp->ev_ident);
622                         break;
623                     case SMBIOD_EV_SHUTDOWN:
624                         iod->iod_flags |= SMBIOD_SHUTDOWN;
625                         break;
626                     case SMBIOD_EV_NEWRQ:
627                         break;
628                 }
629                 if (evp->ev_type & SMBIOD_EV_SYNC) {
630                         SMB_IOD_EVLOCK(iod);
631                         wakeup(evp);
632                         SMB_IOD_EVUNLOCK(iod);
633                 } else
634                         free(evp, M_SMBIOD);
635         }
636 #if 0
637         if (iod->iod_state == SMBIOD_ST_VCACTIVE) {
638                 getnanotime(&tsnow);
639                 timespecsub(&tsnow, &iod->iod_pingtimo);
640                 if (timespeccmp(&tsnow, &iod->iod_lastrqsent, >)) {
641                         smb_smb_echo(vcp, &iod->iod_scred);
642                 }
643         }
644 #endif
645         smb_iod_sendall(iod);
646         smb_iod_recvall(iod);
647         return;
648 }
649
650 void
651 smb_iod_thread(void *arg)
652 {
653         struct smbiod *iod = arg;
654
655         mtx_lock(&Giant);
656
657         /*
658          * Here we assume that the thread structure will be the same
659          * for an entire kthread (kproc, to be more precise) life.
660          */
661         iod->iod_td = curthread;
662         smb_makescred(&iod->iod_scred, iod->iod_td, NULL);
663         while ((iod->iod_flags & SMBIOD_SHUTDOWN) == 0) {
664                 smb_iod_main(iod);
665                 SMBIODEBUG("going to sleep for %d ticks\n", iod->iod_sleeptimo);
666                 if (iod->iod_flags & SMBIOD_SHUTDOWN)
667                         break;
668                 tsleep(&iod->iod_flags, PWAIT, "90idle", iod->iod_sleeptimo);
669         }
670         mtx_unlock(&Giant);
671         kproc_exit(0);
672 }
673
674 int
675 smb_iod_create(struct smb_vc *vcp)
676 {
677         struct smbiod *iod;
678         int error;
679
680         iod = smb_zmalloc(sizeof(*iod), M_SMBIOD, M_WAITOK);
681         iod->iod_id = smb_iod_next++;
682         iod->iod_state = SMBIOD_ST_NOTCONN;
683         iod->iod_vc = vcp;
684         iod->iod_sleeptimo = hz * SMBIOD_SLEEP_TIMO;
685         iod->iod_pingtimo.tv_sec = SMBIOD_PING_TIMO;
686         getnanotime(&iod->iod_lastrqsent);
687         vcp->vc_iod = iod;
688         smb_sl_init(&iod->iod_rqlock, "90rql");
689         TAILQ_INIT(&iod->iod_rqlist);
690         smb_sl_init(&iod->iod_evlock, "90evl");
691         STAILQ_INIT(&iod->iod_evlist);
692         error = kproc_create(smb_iod_thread, iod, &iod->iod_p,
693             RFNOWAIT, 0, "smbiod%d", iod->iod_id);
694         if (error) {
695                 SMBERROR("can't start smbiod: %d", error);
696                 free(iod, M_SMBIOD);
697                 return error;
698         }
699         return 0;
700 }
701
702 int
703 smb_iod_destroy(struct smbiod *iod)
704 {
705         smb_iod_request(iod, SMBIOD_EV_SHUTDOWN | SMBIOD_EV_SYNC, NULL);
706         smb_sl_destroy(&iod->iod_rqlock);
707         smb_sl_destroy(&iod->iod_evlock);
708         free(iod, M_SMBIOD);
709         return 0;
710 }
711
712 int
713 smb_iod_init(void)
714 {
715         return 0;
716 }
717
718 int
719 smb_iod_done(void)
720 {
721         return 0;
722 }
723