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