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
smb_iod_rqprocessed(struct smb_rq * rqp,int error)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
smb_iod_invrq(struct smbiod * iod)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
smb_iod_closetran(struct smbiod * iod)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
smb_iod_dead(struct smbiod * iod)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
smb_iod_connect(struct smbiod * iod)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
smb_iod_disconnect(struct smbiod * iod)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
smb_iod_treeconnect(struct smbiod * iod,struct smb_share * ssp)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
smb_iod_sendrq(struct smbiod * iod,struct smb_rq * rqp)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
smb_iod_recvall(struct smbiod * iod)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
smb_iod_request(struct smbiod * iod,int event,void * ident)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
smb_iod_addrq(struct smb_rq * rqp)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
smb_iod_removerq(struct smb_rq * rqp)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
smb_iod_waitrq(struct smb_rq * rqp)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
smb_iod_sendall(struct smbiod * iod)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
smb_iod_main(struct smbiod * iod)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
smb_iod_thread(void * arg)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
smb_iod_create(struct smb_vc * vcp)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
smb_iod_destroy(struct smbiod * iod)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
smb_iod_init(void)727 smb_iod_init(void)
728 {
729 return 0;
730 }
731
732 int
smb_iod_done(void)733 smb_iod_done(void)
734 {
735 return 0;
736 }
737
738