Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / netproto / ncp / ncp_rq.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  * Routines to prepare request and fetch reply
33  *
34  * $FreeBSD: src/sys/netncp/ncp_rq.c,v 1.1.2.1 2001/05/21 16:27:20 ru Exp $
35  */ 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/mbuf.h>
40 #include <sys/uio.h>
41
42 #include <netncp/ncp.h>
43 #include <netncp/ncp_conn.h>
44 #include <netncp/ncp_rq.h>
45 #include <netncp/ncp_subr.h>
46 #include <netncp/ncp_ncp.h>
47 #include <netncp/ncp_nls.h>
48
49 int
50 ncp_rq_head(struct ncp_rq *rqp, u_int32_t ptype, u_int8_t fn,struct proc *p,
51     struct ucred *cred)
52 {
53         struct mbuf *m;
54         struct ncp_rqhdr *rq;
55         struct ncp_bursthdr *brq;
56         caddr_t pstart;
57
58         bzero(rqp, sizeof(*rqp));
59         rqp->p = p;
60         rqp->cred = cred;
61         m = m_gethdr(M_WAIT, MT_DATA);
62         if (m == NULL) 
63                 return ENOBUFS;         /* if M_WAIT ? */
64         m->m_pkthdr.rcvif = NULL;
65         rqp->rq = rqp->mrq = m;
66         rqp->rp = NULL;
67         switch(ptype) {
68             case NCP_PACKET_BURST:
69                 MH_ALIGN(m, sizeof(*brq) + 24);
70                 m->m_len = sizeof(*brq);
71                 brq = mtod(m, struct ncp_bursthdr *);
72                 brq->bh_type = ptype;
73                 brq->bh_streamtype = 0x2;
74                 pstart = (caddr_t)brq;
75                 break;
76             default:
77                 MH_ALIGN(m, sizeof(*rq) + 2);   /* possible len field in some functions */
78                 m->m_len = sizeof(*rq);
79                 rq = mtod(m, struct ncp_rqhdr *);
80                 rq->type = ptype;
81                 rq->seq = 0;    /* filled later */
82                 rq->fn = fn;
83                 pstart = (caddr_t)rq;
84                 break;
85         }
86         rqp->bpos = pstart + m->m_len;
87         return 0;
88 }
89
90 int
91 ncp_rq_done(struct ncp_rq *rqp) {
92         m_freem(rqp->rq);
93         rqp->rq=NULL;
94         if (rqp->rp) m_freem(rqp->rp);
95         rqp->rp=NULL;
96         return (0);
97 }
98
99 /*
100  * Routines to fill the request
101  */
102 static caddr_t ncp_mchecksize(struct ncp_rq *rqp, int size);
103 #define NCP_RQADD(t)    ((t*)(ncp_mchecksize(rqp,sizeof(t))))
104
105 caddr_t
106 ncp_mchecksize(struct ncp_rq *rqp, int size) {
107         caddr_t bpos1;
108
109         if (size>MLEN)
110                 panic("ncp_mchecksize\n");
111         if (M_TRAILINGSPACE(rqp->mrq)<(size)) {
112                 struct mbuf *m;
113                 m = m_get(M_WAIT, MT_DATA);
114                 m->m_len = 0;
115                 rqp->bpos = mtod(m, caddr_t);
116                 rqp->mrq->m_next = m;
117                 rqp->mrq = m;
118         }
119         rqp->mrq->m_len += size;
120         bpos1 = rqp->bpos;
121         rqp->bpos += size;
122         return bpos1;
123 }
124
125 void
126 ncp_rq_byte(struct ncp_rq *rqp,u_int8_t x) {
127         *NCP_RQADD(u_int8_t)=x;
128 }
129
130 void
131 ncp_rq_word_hl(struct ncp_rq *rqp, u_int16_t x) {
132         setwbe(NCP_RQADD(u_int16_t), 0, x);
133 }
134
135 void
136 ncp_rq_word_lh(struct ncp_rq *rqp, u_int16_t x) {
137         setwle(NCP_RQADD(u_int16_t), 0, x);
138 }
139
140 void
141 ncp_rq_dword_lh(struct ncp_rq *rqp, u_int32_t x) {
142         setdle(NCP_RQADD(u_int32_t), 0, x);
143 }
144
145 void
146 ncp_rq_pathstring(struct ncp_rq *rqp, int size, char *name, struct ncp_nlstables *nt) {
147         struct mbuf *m;
148         int cplen;
149
150         ncp_rq_byte(rqp, size);
151         m = rqp->mrq;
152         cplen = min(size, M_TRAILINGSPACE(m));
153         if (cplen) {
154                 ncp_pathcopy(name, rqp->bpos, cplen, nt);
155                 size -= cplen;
156                 name += cplen;
157                 m->m_len += cplen;
158         }
159         if (size) {
160                 m = m_getm(m, size, MT_DATA, M_WAIT);
161                 while (size > 0){
162                         m = m->m_next;
163                         cplen = min(size, M_TRAILINGSPACE(m));
164                         ncp_pathcopy(name, mtod(m, caddr_t) + m->m_len, cplen, nt);
165                         size -= cplen;
166                         name += cplen;
167                         m->m_len += cplen;
168                 }
169         }
170         rqp->bpos = mtod(m,caddr_t) + m->m_len;
171         rqp->mrq = m;
172         return;
173 }
174
175 int
176 ncp_rq_putanymem(struct ncp_rq *rqp, caddr_t source, int size, int type) {
177         struct mbuf *m;
178         int cplen, error;
179
180         m = rqp->mrq;
181         cplen = min(size, M_TRAILINGSPACE(m));
182         if (cplen) {
183                 if (type==1) {
184                         error = copyin(source, rqp->bpos, cplen);
185                         if (error) return error;
186                 } else
187                         bcopy(source, rqp->bpos, cplen);
188                 size -= cplen;
189                 source += cplen;
190                 m->m_len += cplen;
191         }
192         if (size) {
193                 m = m_getm(m, size, MT_DATA, M_WAIT);
194                 while (size > 0){
195                         m = m->m_next;
196                         cplen = min(size, M_TRAILINGSPACE(m));
197                         if (type==1) {
198                                 error = copyin(source, mtod(m, caddr_t) + m->m_len, cplen);
199                                 if (error) return error;
200                         } else
201                                 bcopy(source, mtod(m, caddr_t) + m->m_len, cplen);
202                         size -= cplen;
203                         source += cplen;
204                         m->m_len += cplen;
205                 }
206         }
207         rqp->bpos = mtod(m,caddr_t) + m->m_len;
208         rqp->mrq = m;
209         return 0;
210 }
211
212 int
213 ncp_rq_mbuf(struct ncp_rq *rqp, struct mbuf *m, int size) {
214
215         rqp->mrq->m_next = m;
216         m->m_next = NULL;
217         if (size != M_COPYALL) m->m_len = size;
218         rqp->bpos = mtod(m,caddr_t) + m->m_len;
219         rqp->mrq = m;
220         return 0;
221 }
222
223 void 
224 ncp_rq_pstring(struct ncp_rq *rqp, char *s) {
225         int len = strlen(s);
226         if (len > 255) {
227                 nwfs_printf("string too long: %s\n", s);
228                 len = 255;
229         }
230         ncp_rq_byte(rqp, len);
231         ncp_rq_mem(rqp, s, len);
232         return;
233 }
234
235 void 
236 ncp_rq_dbase_path(struct ncp_rq *rqp, u_int8_t vol_num, u_int32_t dir_base,
237                     int namelen, u_char *path, struct ncp_nlstables *nt)
238 {
239         int complen;
240
241         ncp_rq_byte(rqp, vol_num);
242         ncp_rq_dword(rqp, dir_base);
243         ncp_rq_byte(rqp, 1);    /* with dirbase */
244         if (path != NULL && path[0]) {
245                 if (namelen < 0) {
246                         namelen = *path++;
247                         ncp_rq_byte(rqp, namelen);
248                         for(; namelen; namelen--) {
249                                 complen = *path++;
250                                 ncp_rq_byte(rqp, complen);
251                                 ncp_rq_mem(rqp, path, complen);
252                                 path += complen;
253                         }
254                 } else {
255                         ncp_rq_byte(rqp, 1);    /* 1 component */
256                         ncp_rq_pathstring(rqp, namelen, path, nt);
257                 }
258         } else {
259                 ncp_rq_byte(rqp, 0);
260                 ncp_rq_byte(rqp, 0);
261         }
262 }
263 /*
264  * fetch reply routines
265  */
266 #define ncp_mspaceleft  (mtod(rqp->mrp,caddr_t)+rqp->mrp->m_len-rqp->bpos)
267
268 u_int8_t
269 ncp_rp_byte(struct ncp_rq *rqp) {
270         if (rqp->mrp == NULL) return 0;
271         if (ncp_mspaceleft < 1) {
272                 rqp->mrp = rqp->mrp->m_next;
273                 if (rqp->mrp == NULL) return 0;
274                 rqp->bpos = mtod(rqp->mrp, caddr_t);
275         }
276         rqp->bpos += 1;
277         return rqp->bpos[-1];
278 }
279
280 u_int16_t
281 ncp_rp_word_lh(struct ncp_rq *rqp) {
282         caddr_t prev = rqp->bpos;
283         u_int16_t t;
284
285         if (rqp->mrp == NULL) return 0;
286         if (ncp_mspaceleft >= 2) {
287                 rqp->bpos += 2;
288                 return getwle(prev,0);
289         }
290         t = *((u_int8_t*)(rqp->bpos));
291         rqp->mrp = rqp->mrp->m_next;
292         if (rqp->mrp == NULL) return 0;
293         ((u_int8_t *)&t)[1] = *((u_int8_t*)(rqp->bpos = mtod(rqp->mrp, caddr_t)));
294         rqp->bpos += 2;
295         return t;
296 }
297
298 u_int16_t
299 ncp_rp_word_hl(struct ncp_rq *rqp) {
300         return (ntohs(ncp_rp_word_lh(rqp)));
301 }
302
303 u_int32_t
304 ncp_rp_dword_hl(struct ncp_rq *rqp) {
305         int togo, rest;
306         caddr_t prev = rqp->bpos;
307         u_int32_t t;
308
309         if (rqp->mrp == NULL) return 0;
310         rest = ncp_mspaceleft;
311         if (rest >= 4) {
312                 rqp->bpos += 4;
313                 return getdbe(prev,0);
314         }
315         togo = 0;
316         while (rest--) {
317                 ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
318         }
319         rqp->mrp = rqp->mrp->m_next;
320         if (rqp->mrp == NULL) return 0;
321         prev = mtod(rqp->mrp, caddr_t);
322         rqp->bpos = prev + 4 - togo;    /* XXX possible low than togo bytes in next mbuf */
323         while (togo < 4) {
324                 ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
325         }
326         return getdbe(&t,0);
327 }
328
329 u_int32_t
330 ncp_rp_dword_lh(struct ncp_rq *rqp) {
331         int rest, togo;
332         caddr_t prev = rqp->bpos;
333         u_int32_t t;
334
335         if (rqp->mrp == NULL) return 0;
336         rest = ncp_mspaceleft;
337         if (rest >= 4) {
338                 rqp->bpos += 4;
339                 return getdle(prev,0);
340         }
341         togo = 0;
342         while (rest--) {
343                 ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
344         }
345         rqp->mrp = rqp->mrp->m_next;
346         if (rqp->mrp == NULL) return 0;
347         prev = mtod(rqp->mrp, caddr_t);
348         rqp->bpos = prev + 4 - togo;    /* XXX possible low than togo bytes in next mbuf */
349         while (togo < 4) {
350                 ((u_int8_t *)&t)[togo++] = *((u_int8_t*)(prev++));
351         }
352         return getdle(&t,0);
353 }
354 void
355 ncp_rp_mem(struct ncp_rq *rqp,caddr_t target, int size) {
356         register struct mbuf *m=rqp->mrp;
357         register unsigned count;
358         
359         while (size > 0) {
360                 if (m==0) {     /* should be panic */
361                         printf("ncp_rp_mem: incomplete copy\n");
362                         return;
363                 }
364                 count = mtod(m,caddr_t)+m->m_len-rqp->bpos;
365                 if (count == 0) {
366                         m=m->m_next;
367                         rqp->bpos=mtod(m,caddr_t);
368                         continue;
369                 }
370                 count = min(count,size);
371                 bcopy(rqp->bpos, target, count);
372                 size -= count;
373                 target += count;
374                 rqp->bpos += count;
375         }
376         rqp->mrp=m;
377         return;
378 }
379
380 int
381 ncp_rp_usermem(struct ncp_rq *rqp,caddr_t target, int size) {
382         register struct mbuf *m=rqp->mrp;
383         register unsigned count;
384         int error;
385         
386         while (size>0) {
387                 if (m==0) {     /* should be panic */
388                         printf("ncp_rp_mem: incomplete copy\n");
389                         return EFAULT;
390                 }
391                 count = mtod(m,caddr_t)+m->m_len-rqp->bpos;
392                 if (count == 0) {
393                         m=m->m_next;
394                         rqp->bpos=mtod(m,caddr_t);
395                         continue;
396                 }
397                 count = min(count,size);
398                 error=copyout(rqp->bpos, target, count);
399                 if (error) return error;
400                 size -= count;
401                 target += count;
402                 rqp->bpos += count;
403         }
404         rqp->mrp=m;
405         return 0;
406 }
407
408 struct mbuf*
409 ncp_rp_mbuf(struct ncp_rq *rqp, int size) {
410         register struct mbuf *m=rqp->mrp, *rm;
411         register unsigned count;
412         
413         rm = m_copym(m, rqp->bpos - mtod(m,caddr_t), size, M_WAIT);
414         while (size > 0) {
415                 if (m == 0) {
416                         printf("ncp_rp_mbuf: can't advance\n");
417                         return rm;
418                 }
419                 count = mtod(m,caddr_t)+ m->m_len - rqp->bpos;
420                 if (count == 0) {
421                         m = m->m_next;
422                         rqp->bpos = mtod(m, caddr_t);
423                         continue;
424                 }
425                 count = min(count, size);
426                 size -= count;
427                 rqp->bpos += count;
428         }
429         rqp->mrp=m;
430         return rm;
431 }
432
433 int
434 nwfs_mbuftouio(mrep, uiop, siz, dpos)
435         struct mbuf **mrep;
436         register struct uio *uiop;
437         int siz;
438         caddr_t *dpos;
439 {
440         register char *mbufcp, *uiocp;
441         register int xfer, left, len;
442         register struct mbuf *mp;
443         long uiosiz;
444         int error = 0;
445
446         mp = *mrep;
447         if (!mp) return 0;
448         mbufcp = *dpos;
449         len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
450         while (siz > 0) {
451                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
452                         return (EFBIG);
453                 left = uiop->uio_iov->iov_len;
454                 uiocp = uiop->uio_iov->iov_base;
455                 if (left > siz)
456                         left = siz;
457                 uiosiz = left;
458                 while (left > 0) {
459                         while (len == 0) {
460                                 mp = mp->m_next;
461                                 if (mp == NULL)
462                                         return (EBADRPC);
463                                 mbufcp = mtod(mp, caddr_t);
464                                 len = mp->m_len;
465                         }
466                         xfer = (left > len) ? len : left;
467 #ifdef notdef
468                         /* Not Yet.. */
469                         if (uiop->uio_iov->iov_op != NULL)
470                                 (*(uiop->uio_iov->iov_op))
471                                 (mbufcp, uiocp, xfer);
472                         else
473 #endif
474                         if (uiop->uio_segflg == UIO_SYSSPACE)
475                                 bcopy(mbufcp, uiocp, xfer);
476                         else
477                                 copyout(mbufcp, uiocp, xfer);
478                         left -= xfer;
479                         len -= xfer;
480                         mbufcp += xfer;
481                         uiocp += xfer;
482                         uiop->uio_offset += xfer;
483                         uiop->uio_resid -= xfer;
484                 }
485                 if (uiop->uio_iov->iov_len <= siz) {
486                         uiop->uio_iovcnt--;
487                         uiop->uio_iov++;
488                 } else {
489                         uiop->uio_iov->iov_base += uiosiz;
490                         uiop->uio_iov->iov_len -= uiosiz;
491                 }
492                 siz -= uiosiz;
493         }
494         *dpos = mbufcp;
495         *mrep = mp;
496         return (error);
497 }
498 /*
499  * copies a uio scatter/gather list to an mbuf chain.
500  * NOTE: can ony handle iovcnt == 1
501  */
502 int
503 nwfs_uiotombuf(uiop, mq, siz, bpos)
504         register struct uio *uiop;
505         struct mbuf **mq;
506         int siz;
507         caddr_t *bpos;
508 {
509         register char *uiocp;
510         register struct mbuf *mp, *mp2;
511         register int xfer, left, mlen;
512         int uiosiz, clflg;
513
514 #ifdef DIAGNOSTIC
515         if (uiop->uio_iovcnt != 1)
516                 panic("nfsm_uiotombuf: iovcnt != 1");
517 #endif
518
519         if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
520                 clflg = 1;
521         else
522                 clflg = 0;
523         mp = mp2 = *mq;
524         while (siz > 0) {
525                 left = uiop->uio_iov->iov_len;
526                 uiocp = uiop->uio_iov->iov_base;
527                 if (left > siz)
528                         left = siz;
529                 uiosiz = left;
530                 while (left > 0) {
531                         mlen = M_TRAILINGSPACE(mp);
532                         if (mlen == 0) {
533                                 MGET(mp, M_WAIT, MT_DATA);
534                                 if (clflg)
535                                         MCLGET(mp, M_WAIT);
536                                 mp->m_len = 0;
537                                 mp2->m_next = mp;
538                                 mp2 = mp;
539                                 mlen = M_TRAILINGSPACE(mp);
540                         }
541                         xfer = (left > mlen) ? mlen : left;
542 #ifdef notdef
543                         /* Not Yet.. */
544                         if (uiop->uio_iov->iov_op != NULL)
545                                 (*(uiop->uio_iov->iov_op))
546                                 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
547                         else
548 #endif
549                         if (uiop->uio_segflg == UIO_SYSSPACE)
550                                 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
551                         else
552                                 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
553                         mp->m_len += xfer;
554                         left -= xfer;
555                         uiocp += xfer;
556                         uiop->uio_offset += xfer;
557                         uiop->uio_resid -= xfer;
558                 }
559                 uiop->uio_iov->iov_base += uiosiz;
560                 uiop->uio_iov->iov_len -= uiosiz;
561                 siz -= uiosiz;
562         }
563         *bpos = mtod(mp, caddr_t)+mp->m_len;
564         *mq = mp;
565         return (0);
566 }