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