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