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