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