proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[dragonfly.git] / sys / netproto / ncp / ncp_subr.c
1 /*
2  * Copyright (c) 1999, 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/netncp/ncp_subr.c,v 1.2.2.1 2001/02/22 08:54:11 bp Exp $
33  * $DragonFly: src/sys/netproto/ncp/ncp_subr.c,v 1.3 2003/06/25 03:56:05 dillon Exp $
34  */
35 #include <sys/param.h>
36 #include <sys/errno.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/time.h>
42 #include <sys/uio.h>
43 #include <sys/mbuf.h>
44
45 #include <netncp/ncp.h>
46 #include <netncp/ncp_conn.h>
47 #include <netncp/ncp_sock.h>
48 #include <netncp/ncp_subr.h>
49 #include <netncp/ncp_rq.h>
50 #include <netncp/ncp_ncp.h>
51 #include <netncp/nwerror.h>
52
53 int ncp_debuglevel = 0;
54
55 struct callout_handle ncp_timer_handle;
56
57 static void ncp_at_exit(struct thread *td);
58 static void ncp_timer(void *arg);
59
60 /*
61  * duplicate string from user space. It should be very-very slow.
62  */
63 char *
64 ncp_str_dup(char *s) 
65 {
66         char *p, bt;
67         int len = 0;
68
69         for (p = s;;p++) {
70                 if (copyin(p, &bt, 1)) return NULL;
71                 len++;
72                 if (bt == 0) break;
73         }
74         MALLOC(p, char*, len, M_NCPDATA, M_WAITOK);
75         copyin(s, p, len);
76         return p;
77 }
78
79
80 void
81 ncp_at_exit(struct thread *td)
82 {
83         struct ncp_conn *ncp, *nncp;
84         struct ucred *cred;
85
86         KKASSERT(td->td_proc);
87         cred = td->td_proc->p_ucred;
88
89         if (ncp_conn_putprochandles(td) == 0) return;
90
91         ncp_conn_locklist(LK_EXCLUSIVE, td);
92         for (ncp = SLIST_FIRST(&conn_list); ncp; ncp = nncp) {
93                 nncp = SLIST_NEXT(ncp, nc_next);
94                 if (ncp->ref_cnt != 0) continue;
95                 if (ncp_conn_lock(ncp, td, cred, NCPM_READ|NCPM_EXECUTE|NCPM_WRITE))
96                         continue;
97                 if (ncp_disconnect(ncp) != 0)
98                         ncp_conn_unlock(ncp, td);
99         }
100         ncp_conn_unlocklist(td);
101 }
102
103 int
104 ncp_init(void) 
105 {
106         ncp_conn_init();
107         if (at_exit(ncp_at_exit)) {
108                 NCPFATAL("can't register at_exit handler\n");
109                 return ENOMEM;
110         }
111         ncp_timer_handle = timeout(ncp_timer,NULL,NCP_TIMER_TICK);
112         return 0;
113 }
114
115 void
116 ncp_done(void) 
117 {
118         struct ncp_conn *ncp, *nncp;
119         struct thread *td = curthread;  /* XXX */
120         struct ucred *cred;
121
122         KKASSERT(td->td_proc);
123         cred = td->td_proc->p_ucred;
124         
125         untimeout(ncp_timer,NULL,ncp_timer_handle);
126         rm_at_exit(ncp_at_exit);
127         ncp_conn_locklist(LK_EXCLUSIVE, td);
128         for (ncp = SLIST_FIRST(&conn_list); ncp; ncp = nncp) {
129                 nncp = SLIST_NEXT(ncp, nc_next);
130                 ncp->ref_cnt = 0;
131                 if (ncp_conn_lock(ncp, td, cred,NCPM_READ|NCPM_EXECUTE|NCPM_WRITE)) {
132                         NCPFATAL("Can't lock connection !\n");
133                         continue;
134                 }
135                 if (ncp_disconnect(ncp) != 0)
136                         ncp_conn_unlock(ncp, td);
137         }
138         ncp_conn_unlocklist(td);
139 }
140
141
142 /* tick every second and check for watch dog packets and lost connections */
143 static void
144 ncp_timer(void *arg){
145         struct ncp_conn *conn;
146
147         if(ncp_conn_locklist(LK_SHARED | LK_NOWAIT, NULL) == 0) {
148                 SLIST_FOREACH(conn, &conn_list, nc_next)
149                         ncp_check_conn(conn);
150                 ncp_conn_unlocklist(NULL);
151         }
152         ncp_timer_handle = timeout(ncp_timer,NULL,NCP_TIMER_TICK);
153 }
154
155 int
156 ncp_get_bindery_object_id(struct ncp_conn *conn, 
157                 u_int16_t object_type, char *object_name, 
158                 struct ncp_bindery_object *target,
159                 struct thread *td,struct ucred *cred)
160 {
161         int error;
162         DECLARE_RQ;
163
164         NCP_RQ_HEAD_S(23,53,td,cred);
165         ncp_rq_word_hl(rqp, object_type);
166         ncp_rq_pstring(rqp, object_name);
167         checkbad(ncp_request(conn,rqp));
168         if (rqp->rpsize < 54) {
169                 printf("ncp_rp_size %d < 54\n", rqp->rpsize);
170                 error = EINVAL;
171                 goto bad;
172         }
173         target->object_id = ncp_rp_dword_hl(rqp);
174         target->object_type = ncp_rp_word_hl(rqp);
175         ncp_rp_mem(rqp,(caddr_t)target->object_name, 48);
176         NCP_RQ_EXIT;
177         return error;
178 }
179
180 int
181 ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) {
182         int error = 0, len = 0, retlen=0, tsiz, burstio;
183         DECLARE_RQ;
184
185         tsiz = uiop->uio_resid;
186 #ifdef NCPBURST
187         burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
188 #else
189         burstio = 0;
190 #endif
191
192         while (tsiz > 0) {
193                 if (!burstio) {
194                         len = min(4096 - (uiop->uio_offset % 4096), tsiz);
195                         len = min(len, conn->buffer_size);
196                         NCP_RQ_HEAD(72,uiop->uio_td,cred);
197                         ncp_rq_byte(rqp, 0);
198                         ncp_rq_mem(rqp, (caddr_t)file, 6);
199                         ncp_rq_dword(rqp, htonl(uiop->uio_offset));
200                         ncp_rq_word(rqp, htons(len));
201                         checkbad(ncp_request(conn,rqp));
202                         retlen = ncp_rp_word_hl(rqp);
203                         if (uiop->uio_offset & 1)
204                                 ncp_rp_byte(rqp);
205                         error = nwfs_mbuftouio(&rqp->mrp,uiop,retlen,&rqp->bpos);
206                         NCP_RQ_EXIT;
207                 } else {
208 #ifdef NCPBURST
209                         error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
210 #endif
211                 }
212                 if (error) break;
213                 tsiz -= retlen;
214                 if (retlen < len)
215                         break;
216         }
217         return (error);
218 }
219
220 int
221 ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
222 {
223         int error = 0, len, tsiz, backup;
224         DECLARE_RQ;
225
226         if (uiop->uio_iovcnt != 1) {
227                 printf("%s: can't handle iovcnt>1 !!!\n", __FUNCTION__);
228                 return EIO;
229         }
230         tsiz = uiop->uio_resid;
231         while (tsiz > 0) {
232                 len = min(4096 - (uiop->uio_offset % 4096), tsiz);
233                 len = min(len, conn->buffer_size);
234                 if (len == 0) {
235                         printf("gotcha!\n");
236                 }
237                 /* rq head */
238                 NCP_RQ_HEAD(73,uiop->uio_td,cred);
239                 ncp_rq_byte(rqp, 0);
240                 ncp_rq_mem(rqp, (caddr_t)file, 6);
241                 ncp_rq_dword(rqp, htonl(uiop->uio_offset));
242                 ncp_rq_word_hl(rqp, len);
243                 nwfs_uiotombuf(uiop,&rqp->mrq,len,&rqp->bpos);
244                 checkbad(ncp_request(conn,rqp));
245                 if (len == 0)
246                         break;
247                 NCP_RQ_EXIT;
248                 if (error) {
249                         backup = len;
250                         uiop->uio_iov->iov_base -= backup;
251                         uiop->uio_iov->iov_len += backup;
252                         uiop->uio_offset -= backup;
253                         uiop->uio_resid += backup;
254                         break;
255                 }
256                 tsiz -= len;
257         }
258         if (error)
259                 uiop->uio_resid = tsiz;
260         switch (error) {
261             case NWE_INSUFFICIENT_SPACE:
262                 error = ENOSPC;
263                 break;
264         }
265         return (error);
266 }