Clean up routing code before I parallelize it.
[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.6 2004/09/16 23:01:34 joerg 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(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         callout_init(&ncp_timer_handle);
112         callout_reset(&ncp_timer_handle, NCP_TIMER_TICK, ncp_timer, NULL);
113         return 0;
114 }
115
116 void
117 ncp_done(void) 
118 {
119         struct ncp_conn *ncp, *nncp;
120         struct thread *td = curthread;  /* XXX */
121         struct ucred *cred;
122
123         KKASSERT(td->td_proc);
124         cred = td->td_proc->p_ucred;
125
126         callout_stop(&ncp_timer_handle);
127         rm_at_exit(ncp_at_exit);
128         ncp_conn_locklist(LK_EXCLUSIVE, td);
129         for (ncp = SLIST_FIRST(&conn_list); ncp; ncp = nncp) {
130                 nncp = SLIST_NEXT(ncp, nc_next);
131                 ncp->ref_cnt = 0;
132                 if (ncp_conn_lock(ncp, td, cred,NCPM_READ|NCPM_EXECUTE|NCPM_WRITE)) {
133                         NCPFATAL("Can't lock connection !\n");
134                         continue;
135                 }
136                 if (ncp_disconnect(ncp) != 0)
137                         ncp_conn_unlock(ncp, td);
138         }
139         ncp_conn_unlocklist(td);
140 }
141
142
143 /* tick every second and check for watch dog packets and lost connections */
144 static void
145 ncp_timer(void *arg)
146 {
147         struct ncp_conn *conn;
148
149         if(ncp_conn_locklist(LK_SHARED | LK_NOWAIT, NULL) == 0) {
150                 SLIST_FOREACH(conn, &conn_list, nc_next)
151                         ncp_check_conn(conn);
152                 ncp_conn_unlocklist(NULL);
153         }
154         callout_reset(&ncp_timer_handle, NCP_TIMER_TICK, ncp_timer, NULL);
155 }
156
157 int
158 ncp_get_bindery_object_id(struct ncp_conn *conn, 
159                 u_int16_t object_type, char *object_name, 
160                 struct ncp_bindery_object *target,
161                 struct thread *td,struct ucred *cred)
162 {
163         int error;
164         DECLARE_RQ;
165
166         NCP_RQ_HEAD_S(23,53,td,cred);
167         ncp_rq_word_hl(rqp, object_type);
168         ncp_rq_pstring(rqp, object_name);
169         checkbad(ncp_request(conn,rqp));
170         if (rqp->rpsize < 54) {
171                 printf("ncp_rp_size %d < 54\n", rqp->rpsize);
172                 error = EINVAL;
173                 goto bad;
174         }
175         target->object_id = ncp_rp_dword_hl(rqp);
176         target->object_type = ncp_rp_word_hl(rqp);
177         ncp_rp_mem(rqp,(caddr_t)target->object_name, 48);
178         NCP_RQ_EXIT;
179         return error;
180 }
181
182 int
183 ncp_read(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred) {
184         int error = 0, len = 0, retlen=0, tsiz, burstio;
185         DECLARE_RQ;
186
187         tsiz = uiop->uio_resid;
188 #ifdef NCPBURST
189         burstio = (ncp_burst_enabled && tsiz > conn->buffer_size);
190 #else
191         burstio = 0;
192 #endif
193
194         while (tsiz > 0) {
195                 if (!burstio) {
196                         len = min(4096 - (uiop->uio_offset % 4096), tsiz);
197                         len = min(len, conn->buffer_size);
198                         NCP_RQ_HEAD(72,uiop->uio_td,cred);
199                         ncp_rq_byte(rqp, 0);
200                         ncp_rq_mem(rqp, (caddr_t)file, 6);
201                         ncp_rq_dword(rqp, htonl(uiop->uio_offset));
202                         ncp_rq_word(rqp, htons(len));
203                         checkbad(ncp_request(conn,rqp));
204                         retlen = ncp_rp_word_hl(rqp);
205                         if (uiop->uio_offset & 1)
206                                 ncp_rp_byte(rqp);
207                         error = nwfs_mbuftouio(&rqp->mrp,uiop,retlen,&rqp->bpos);
208                         NCP_RQ_EXIT;
209                 } else {
210 #ifdef NCPBURST
211                         error = ncp_burst_read(conn, file, tsiz, &len, &retlen, uiop, cred);
212 #endif
213                 }
214                 if (error) break;
215                 tsiz -= retlen;
216                 if (retlen < len)
217                         break;
218         }
219         return (error);
220 }
221
222 int
223 ncp_write(struct ncp_conn *conn, ncp_fh *file, struct uio *uiop, struct ucred *cred)
224 {
225         int error = 0, len, tsiz, backup;
226         DECLARE_RQ;
227
228         if (uiop->uio_iovcnt != 1) {
229                 printf("%s: can't handle iovcnt>1 !!!\n", __FUNCTION__);
230                 return EIO;
231         }
232         tsiz = uiop->uio_resid;
233         while (tsiz > 0) {
234                 len = min(4096 - (uiop->uio_offset % 4096), tsiz);
235                 len = min(len, conn->buffer_size);
236                 if (len == 0) {
237                         printf("gotcha!\n");
238                 }
239                 /* rq head */
240                 NCP_RQ_HEAD(73,uiop->uio_td,cred);
241                 ncp_rq_byte(rqp, 0);
242                 ncp_rq_mem(rqp, (caddr_t)file, 6);
243                 ncp_rq_dword(rqp, htonl(uiop->uio_offset));
244                 ncp_rq_word_hl(rqp, len);
245                 nwfs_uiotombuf(uiop,&rqp->mrq,len,&rqp->bpos);
246                 checkbad(ncp_request(conn,rqp));
247                 if (len == 0)
248                         break;
249                 NCP_RQ_EXIT;
250                 if (error) {
251                         backup = len;
252                         uiop->uio_iov->iov_base -= backup;
253                         uiop->uio_iov->iov_len += backup;
254                         uiop->uio_offset -= backup;
255                         uiop->uio_resid += backup;
256                         break;
257                 }
258                 tsiz -= len;
259         }
260         if (error)
261                 uiop->uio_resid = tsiz;
262         switch (error) {
263             case NWE_INSUFFICIENT_SPACE:
264                 error = ENOSPC;
265                 break;
266         }
267         return (error);
268 }