1 /* $NetBSD: subr_mchain.c,v 1.10 2005/02/26 22:39:50 perry Exp $ */
2
3 /*
4 * Copyright (c) 2000, 2001 Boris Popov
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * FreeBSD: src/sys/kern/subr_mchain.c,v 1.4 2002/02/21 16:23:38 bp Exp
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: subr_mchain.c,v 1.10 2005/02/26 22:39:50 perry Exp $");
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/errno.h>
43 #include <sys/mbuf.h>
44 #include <sys/uio.h>
45
46 #include <netsmb/mchain.h>
47
48 #define MBERROR(format, args...) printf("%s(%d): "format, __func__ , \
49 __LINE__ ,## args)
50
51 #define MBPANIC(format, args...) printf("%s(%d): "format, __func__ , \
52 __LINE__ ,## args)
53
54 #ifdef __NetBSD__
55 static struct mbuf *
56 m_getm(struct mbuf *m, int len, int how, int type)
57 {
58 struct mbuf *top, *tail, *mp, *mtail = NULL;
59
60 KASSERT(len >= 0);
61
62 mp = m_get(how, type);
63 if (mp == NULL)
64 return (NULL);
65 else if (len > MINCLSIZE) {
66 m_clget(mp, how);
67 if ((mp->m_flags & M_EXT) == 0) {
68 m_free(mp);
69 return (NULL);
70 }
71 }
72 mp->m_len = 0;
73 len -= M_TRAILINGSPACE(mp);
74
75 if (m != NULL)
76 for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next);
77 else
78 m = mp;
79
80 top = tail = mp;
81 while (len > 0) {
82 mp = m_get(how, type);
83 if (mp == NULL)
84 goto failed;
85
86 tail->m_next = mp;
87 tail = mp;
88 if (len > MINCLSIZE) {
89 m_clget(mp, how);
90 if ((mp->m_flags & M_EXT) == 0)
91 goto failed;
92 }
93
94 mp->m_len = 0;
95 len -= M_TRAILINGSPACE(mp);
96 }
97
98 if (mtail != NULL)
99 mtail->m_next = top;
100 return (m);
101
102 failed:
103 m_freem(top);
104 return (NULL);
105 }
106
107 #endif /* __NetBSD__ */
108
109 /*
110 * Various helper functions
111 */
112 int
113 m_fixhdr(struct mbuf *m0)
114 {
115 struct mbuf *m = m0;
116 int len = 0;
117
118 while (m) {
119 len += m->m_len;
120 m = m->m_next;
121 }
122 m0->m_pkthdr.len = len;
123 return len;
124 }
125
126 int
127 mb_init(struct mbchain *mbp)
128 {
129 struct mbuf *m;
130
131 m = m_gethdr(M_WAIT, MT_DATA);
132 if (m == NULL)
133 return ENOBUFS;
134 m->m_len = 0;
135 mb_initm(mbp, m);
136 return 0;
137 }
138
139 void
140 mb_initm(struct mbchain *mbp, struct mbuf *m)
141 {
142 bzero(mbp, sizeof(*mbp));
143 mbp->mb_top = mbp->mb_cur = m;
144 mbp->mb_mleft = M_TRAILINGSPACE(m);
145 }
146
147 void
148 mb_done(struct mbchain *mbp)
149 {
150 if (mbp->mb_top) {
151 m_freem(mbp->mb_top);
152 mbp->mb_top = NULL;
153 }
154 }
155
156 struct mbuf *
157 mb_detach(struct mbchain *mbp)
158 {
159 struct mbuf *m;
160
161 m = mbp->mb_top;
162 mbp->mb_top = NULL;
163 return m;
164 }
165
166 int
167 mb_fixhdr(struct mbchain *mbp)
168 {
169 return mbp->mb_top->m_pkthdr.len = m_fixhdr(mbp->mb_top);
170 }
171
172 /*
173 * Check if object of size 'size' fit to the current position and
174 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
175 * Return pointer to the object placeholder or NULL if any error occurred.
176 * Note: size should be <= MLEN
177 */
178 caddr_t
179 mb_reserve(struct mbchain *mbp, int size)
180 {
181 struct mbuf *m, *mn;
182 caddr_t bpos;
183
184 if (size > MLEN)
185 panic("mb_reserve: size = %d", size);
186 m = mbp->mb_cur;
187 if (mbp->mb_mleft < size) {
188 mn = m_get(M_WAIT, MT_DATA);
189 if (mn == NULL)
190 return NULL;
191 mbp->mb_cur = m->m_next = mn;
192 m = mn;
193 m->m_len = 0;
194 mbp->mb_mleft = M_TRAILINGSPACE(m);
195 }
196 mbp->mb_mleft -= size;
197 mbp->mb_count += size;
198 bpos = mtod(m, caddr_t) + m->m_len;
199 m->m_len += size;
200 return bpos;
201 }
202
203 int
204 mb_put_uint8(struct mbchain *mbp, u_int8_t x)
205 {
206 return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
207 }
208
209 int
210 mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
211 {
212 x = htobe16(x);
213 return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
214 }
215
216 int
217 mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
218 {
219 x = htole16(x);
220 return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
221 }
222
223 int
224 mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
225 {
226 x = htobe32(x);
227 return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
228 }
229
230 int
231 mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
232 {
233 x = htole32(x);
234 return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
235 }
236
237 int
238 mb_put_int64be(struct mbchain *mbp, int64_t x)
239 {
240 x = htobe64(x);
241 return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
242 }
243
244 int
245 mb_put_int64le(struct mbchain *mbp, int64_t x)
246 {
247 x = htole64(x);
248 return mb_put_mem(mbp, (caddr_t)&x, sizeof(x), MB_MSYSTEM);
249 }
250
251 int
252 mb_put_mem(struct mbchain *mbp, const char *source, int size, int type)
253 {
254 struct mbuf *m;
255 caddr_t dst;
256 caddr_t src;
257 int cplen, error, mleft, count;
258
259 m = mbp->mb_cur;
260 mleft = mbp->mb_mleft;
261
262 while (size > 0) {
263 if (mleft == 0) {
264 if (m->m_next == NULL) {
265 m = m_getm(m, size, M_WAIT, MT_DATA);
266 if (m == NULL)
267 return ENOBUFS;
268 }
269 m = m->m_next;
270 mleft = M_TRAILINGSPACE(m);
271 continue;
272 }
273 cplen = mleft > size ? size : mleft;
274 dst = mtod(m, caddr_t) + m->m_len;
275 switch (type) {
276 case MB_MCUSTOM:
277 error = mbp->mb_copy(mbp, (caddr_t)source, dst, cplen);
278 if (error)
279 return error;
280 break;
281 case MB_MINLINE:
282 for (src = (caddr_t)source, count = cplen; count; count--)
283 *dst++ = *src++;
284 break;
285 case MB_MSYSTEM:
286 bcopy(source, dst, cplen);
287 break;
288 case MB_MUSER:
289 error = copyin(source, dst, cplen);
290 if (error)
291 return error;
292 break;
293 case MB_MZERO:
294 bzero(dst, cplen);
295 break;
296 }
297 size -= cplen;
298 source += cplen;
299 m->m_len += cplen;
300 mleft -= cplen;
301 mbp->mb_count += cplen;
302 }
303 mbp->mb_cur = m;
304 mbp->mb_mleft = mleft;
305 return 0;
306 }
307
308 int
309 mb_put_mbuf(struct mbchain *mbp, struct mbuf *m)
310 {
311 mbp->mb_cur->m_next = m;
312 while (m) {
313 mbp->mb_count += m->m_len;
314 if (m->m_next == NULL)
315 break;
316 m = m->m_next;
317 }
318 mbp->mb_mleft = M_TRAILINGSPACE(m);
319 mbp->mb_cur = m;
320 return 0;
321 }
322
323 /*
324 * copies a uio scatter/gather list to an mbuf chain.
325 */
326 int
327 mb_put_uio(struct mbchain *mbp, struct uio *uiop, int size)
328 {
329 long left;
330 int mtype, error;
331
332 mtype = (uiop->uio_segflg == UIO_SYSSPACE) ? MB_MSYSTEM : MB_MUSER;
333
334 while (size > 0 && uiop->uio_resid) {
335 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
336 return EFBIG;
337 left = uiop->uio_iov->iov_len;
338 if (left == 0) {
339 uiop->uio_iov++;
340 uiop->uio_iovcnt--;
341 continue;
342 }
343 if (left > size)
344 left = size;
345 error = mb_put_mem(mbp, uiop->uio_iov->iov_base, left, mtype);
346 if (error)
347 return error;
348 uiop->uio_offset += left;
349 uiop->uio_resid -= left;
350 uiop->uio_iov->iov_base =
351 (char *)uiop->uio_iov->iov_base + left;
352 uiop->uio_iov->iov_len -= left;
353 size -= left;
354 }
355 return 0;
356 }
357
358 /*
359 * Routines for fetching data from an mbuf chain
360 */
361 int
362 md_init(struct mdchain *mdp)
363 {
364 struct mbuf *m;
365
366 m = m_gethdr(M_WAIT, MT_DATA);
367 if (m == NULL)
368 return ENOBUFS;
369 m->m_len = 0;
370 md_initm(mdp, m);
371 return 0;
372 }
373
374 void
375 md_initm(struct mdchain *mdp, struct mbuf *m)
376 {
377 bzero(mdp, sizeof(*mdp));
378 mdp->md_top = mdp->md_cur = m;
379 mdp->md_pos = mtod(m, u_char*);
380 }
381
382 void
383 md_done(struct mdchain *mdp)
384 {
385 if (mdp->md_top) {
386 m_freem(mdp->md_top);
387 mdp->md_top = NULL;
388 }
389 }
390
391 /*
392 * Append a separate mbuf chain. It is caller responsibility to prevent
393 * multiple calls to fetch/record routines.
394 */
395 void
396 md_append_record(struct mdchain *mdp, struct mbuf *top)
397 {
398 struct mbuf *m;
399
400 if (mdp->md_top == NULL) {
401 md_initm(mdp, top);
402 return;
403 }
404 m = mdp->md_top;
405 while (m->m_nextpkt)
406 m = m->m_nextpkt;
407 m->m_nextpkt = top;
408 top->m_nextpkt = NULL;
409 return;
410 }
411
412 /*
413 * Put next record in place of existing
414 */
415 int
416 md_next_record(struct mdchain *mdp)
417 {
418 struct mbuf *m;
419
420 if (mdp->md_top == NULL)
421 return ENOENT;
422 m = mdp->md_top->m_nextpkt;
423 md_done(mdp);
424 if (m == NULL)
425 return ENOENT;
426 md_initm(mdp, m);
427 return 0;
428 }
429
430 int
431 md_get_uint8(struct mdchain *mdp, u_int8_t *x)
432 {
433 return md_get_mem(mdp, x, 1, MB_MINLINE);
434 }
435
436 int
437 md_get_uint16(struct mdchain *mdp, u_int16_t *x)
438 {
439 return md_get_mem(mdp, (caddr_t)x, 2, MB_MINLINE);
440 }
441
442 int
443 md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
444 {
445 u_int16_t v;
446 int error = md_get_uint16(mdp, &v);
447
448 *x = le16toh(v);
449 return error;
450 }
451
452 int
453 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
454 u_int16_t v;
455 int error = md_get_uint16(mdp, &v);
456
457 *x = be16toh(v);
458 return error;
459 }
460
461 int
462 md_get_uint32(struct mdchain *mdp, u_int32_t *x)
463 {
464 return md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE);
465 }
466
467 int
468 md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
469 {
470 u_int32_t v;
471 int error;
472
473 error = md_get_uint32(mdp, &v);
474 *x = be32toh(v);
475 return error;
476 }
477
478 int
479 md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
480 {
481 u_int32_t v;
482 int error;
483
484 error = md_get_uint32(mdp, &v);
485 *x = le32toh(v);
486 return error;
487 }
488
489 int
490 md_get_int64(struct mdchain *mdp, int64_t *x)
491 {
492 return md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE);
493 }
494
495 int
496 md_get_int64be(struct mdchain *mdp, int64_t *x)
497 {
498 int64_t v;
499 int error;
500
501 error = md_get_int64(mdp, &v);
502 *x = be64toh(v);
503 return error;
504 }
505
506 int
507 md_get_int64le(struct mdchain *mdp, int64_t *x)
508 {
509 int64_t v;
510 int error;
511
512 error = md_get_int64(mdp, &v);
513 *x = le64toh(v);
514 return error;
515 }
516
517 int
518 md_get_mem(struct mdchain *mdp, caddr_t target, int size, int type)
519 {
520 struct mbuf *m = mdp->md_cur;
521 int error;
522 u_int count;
523 u_char *s;
524
525 while (size > 0) {
526 if (m == NULL) {
527 #ifdef MCHAIN_DEBUG
528 MBERROR("incomplete copy\n");
529 #endif
530 return EBADRPC;
531 }
532 s = mdp->md_pos;
533 count = mtod(m, u_char*) + m->m_len - s;
534 if (count == 0) {
535 mdp->md_cur = m = m->m_next;
536 if (m)
537 s = mdp->md_pos = mtod(m, caddr_t);
538 continue;
539 }
540 if (count > size)
541 count = size;
542 size -= count;
543 mdp->md_pos += count;
544 if (target == NULL)
545 continue;
546 switch (type) {
547 case MB_MUSER:
548 error = copyout(s, target, count);
549 if (error)
550 return error;
551 break;
552 case MB_MSYSTEM:
553 bcopy(s, target, count);
554 break;
555 case MB_MINLINE:
556 while (count--)
557 *target++ = *s++;
558 continue;
559 }
560 target += count;
561 }
562 return 0;
563 }
564
565 int
566 md_get_mbuf(struct mdchain *mdp, int size, struct mbuf **ret)
567 {
568 struct mbuf *m = mdp->md_cur, *rm;
569
570 rm = m_copym(m, mdp->md_pos - mtod(m, u_char*), size, M_WAIT);
571 if (rm == NULL)
572 return EBADRPC;
573 md_get_mem(mdp, NULL, size, MB_MZERO);
574 *ret = rm;
575 return 0;
576 }
577
578 int
579 md_get_uio(struct mdchain *mdp, struct uio *uiop, int size)
580 {
581 char *uiocp;
582 long left;
583 int mtype, error;
584
585 mtype = (uiop->uio_segflg == UIO_SYSSPACE) ? MB_MSYSTEM : MB_MUSER;
586 while (size > 0 && uiop->uio_resid) {
587 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
588 return EFBIG;
589 left = uiop->uio_iov->iov_len;
590 if (left == 0) {
591 uiop->uio_iov++;
592 uiop->uio_iovcnt--;
593 continue;
594 }
595 uiocp = uiop->uio_iov->iov_base;
596 if (left > size)
597 left = size;
598 error = md_get_mem(mdp, uiocp, left, mtype);
599 if (error)
600 return error;
601 uiop->uio_offset += left;
602 uiop->uio_resid -= left;
603 uiop->uio_iov->iov_base =
604 (char *)uiop->uio_iov->iov_base + left;
605 uiop->uio_iov->iov_len -= left;
606 size -= left;
607 }
608 return 0;
609 }
Cache object: cc95ca6ea234434f6fc466aa9b72d9a2
|