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