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