1 /* $NetBSD: subr_mchain.c,v 1.13.18.1 2010/07/22 20:36:22 riz 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.13.18.1 2010/07/22 20:36:22 riz 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 <uvm/uvm_extern.h>
47
48 #include <netsmb/mchain.h>
49
50 #define MBERROR(format, args...) printf("%s(%d): "format, __func__ , \
51 __LINE__ ,## args)
52
53 #define MBPANIC(format, args...) printf("%s(%d): "format, __func__ , \
54 __LINE__ ,## args)
55
56 #ifdef __NetBSD__
57 static struct mbuf *
58 m_getm(struct mbuf *m, size_t len, int how, int type)
59 {
60 struct mbuf *top, *tail, *mp, *mtail = NULL;
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 size_t 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, size_t size)
180 {
181 struct mbuf *m, *mn;
182 caddr_t bpos;
183
184 if (size > MLEN)
185 panic("mb_reserve: size = %zu", 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, size_t size, int type)
253 {
254 struct mbuf *m;
255 char *dst;
256 const char *src;
257 int error;
258 size_t cplen, mleft, count;
259
260 m = mbp->mb_cur;
261 mleft = mbp->mb_mleft;
262
263 while (size > 0) {
264 if (mleft == 0) {
265 if (m->m_next == NULL) {
266 m = m_getm(m, size, M_WAIT, MT_DATA);
267 if (m == NULL)
268 return ENOBUFS;
269 }
270 m = m->m_next;
271 mleft = M_TRAILINGSPACE(m);
272 continue;
273 }
274 cplen = mleft > size ? size : mleft;
275 dst = mtod(m, caddr_t) + m->m_len;
276 switch (type) {
277 case MB_MCUSTOM:
278 error = mbp->mb_copy(mbp, source, dst, cplen);
279 if (error)
280 return error;
281 break;
282 case MB_MINLINE:
283 for (src = source, count = cplen; count; count--)
284 *dst++ = *src++;
285 break;
286 case MB_MSYSTEM:
287 bcopy(source, dst, cplen);
288 break;
289 case MB_MUSER:
290 error = copyin(source, dst, cplen);
291 if (error)
292 return error;
293 break;
294 case MB_MZERO:
295 bzero(dst, cplen);
296 break;
297 }
298 size -= cplen;
299 source += cplen;
300 m->m_len += cplen;
301 mleft -= cplen;
302 mbp->mb_count += cplen;
303 }
304 mbp->mb_cur = m;
305 mbp->mb_mleft = mleft;
306 return 0;
307 }
308
309 int
310 mb_put_mbuf(struct mbchain *mbp, struct mbuf *m)
311 {
312 mbp->mb_cur->m_next = m;
313 while (m) {
314 mbp->mb_count += m->m_len;
315 if (m->m_next == NULL)
316 break;
317 m = m->m_next;
318 }
319 mbp->mb_mleft = M_TRAILINGSPACE(m);
320 mbp->mb_cur = m;
321 return 0;
322 }
323
324 /*
325 * copies a uio scatter/gather list to an mbuf chain.
326 */
327 int
328 mb_put_uio(struct mbchain *mbp, struct uio *uiop, size_t size)
329 {
330 size_t left;
331 int mtype, error;
332
333 mtype = VMSPACE_IS_KERNEL_P(uiop->uio_vmspace) ? MB_MSYSTEM : MB_MUSER;
334
335 while (size > 0 && uiop->uio_resid) {
336 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
337 return EFBIG;
338 left = uiop->uio_iov->iov_len;
339 if (left == 0) {
340 uiop->uio_iov++;
341 uiop->uio_iovcnt--;
342 continue;
343 }
344 if (left > size)
345 left = size;
346 error = mb_put_mem(mbp, uiop->uio_iov->iov_base, left, mtype);
347 if (error)
348 return error;
349 uiop->uio_offset += left;
350 uiop->uio_resid -= left;
351 uiop->uio_iov->iov_base =
352 (char *)uiop->uio_iov->iov_base + left;
353 uiop->uio_iov->iov_len -= left;
354 size -= left;
355 }
356 return 0;
357 }
358
359 /*
360 * Routines for fetching data from an mbuf chain
361 */
362 int
363 md_init(struct mdchain *mdp)
364 {
365 struct mbuf *m;
366
367 m = m_gethdr(M_WAIT, MT_DATA);
368 if (m == NULL)
369 return ENOBUFS;
370 m->m_len = 0;
371 md_initm(mdp, m);
372 return 0;
373 }
374
375 void
376 md_initm(struct mdchain *mdp, struct mbuf *m)
377 {
378 bzero(mdp, sizeof(*mdp));
379 mdp->md_top = mdp->md_cur = m;
380 mdp->md_pos = mtod(m, u_char*);
381 }
382
383 void
384 md_done(struct mdchain *mdp)
385 {
386 if (mdp->md_top) {
387 m_freem(mdp->md_top);
388 mdp->md_top = NULL;
389 }
390 }
391
392 /*
393 * Append a separate mbuf chain. It is caller responsibility to prevent
394 * multiple calls to fetch/record routines.
395 */
396 void
397 md_append_record(struct mdchain *mdp, struct mbuf *top)
398 {
399 struct mbuf *m;
400
401 if (mdp->md_top == NULL) {
402 md_initm(mdp, top);
403 return;
404 }
405 m = mdp->md_top;
406 while (m->m_nextpkt)
407 m = m->m_nextpkt;
408 m->m_nextpkt = top;
409 top->m_nextpkt = NULL;
410 return;
411 }
412
413 /*
414 * Put next record in place of existing
415 */
416 int
417 md_next_record(struct mdchain *mdp)
418 {
419 struct mbuf *m;
420
421 if (mdp->md_top == NULL)
422 return ENOENT;
423 m = mdp->md_top->m_nextpkt;
424 md_done(mdp);
425 if (m == NULL)
426 return ENOENT;
427 md_initm(mdp, m);
428 return 0;
429 }
430
431 int
432 md_get_uint8(struct mdchain *mdp, u_int8_t *x)
433 {
434 return md_get_mem(mdp, x, 1, MB_MINLINE);
435 }
436
437 int
438 md_get_uint16(struct mdchain *mdp, u_int16_t *x)
439 {
440 return md_get_mem(mdp, (caddr_t)x, 2, MB_MINLINE);
441 }
442
443 int
444 md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
445 {
446 u_int16_t v;
447 int error = md_get_uint16(mdp, &v);
448
449 *x = le16toh(v);
450 return error;
451 }
452
453 int
454 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
455 u_int16_t v;
456 int error = md_get_uint16(mdp, &v);
457
458 *x = be16toh(v);
459 return error;
460 }
461
462 int
463 md_get_uint32(struct mdchain *mdp, u_int32_t *x)
464 {
465 return md_get_mem(mdp, (caddr_t)x, 4, MB_MINLINE);
466 }
467
468 int
469 md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
470 {
471 u_int32_t v;
472 int error;
473
474 error = md_get_uint32(mdp, &v);
475 *x = be32toh(v);
476 return error;
477 }
478
479 int
480 md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
481 {
482 u_int32_t v;
483 int error;
484
485 error = md_get_uint32(mdp, &v);
486 *x = le32toh(v);
487 return error;
488 }
489
490 int
491 md_get_int64(struct mdchain *mdp, int64_t *x)
492 {
493 return md_get_mem(mdp, (caddr_t)x, 8, MB_MINLINE);
494 }
495
496 int
497 md_get_int64be(struct mdchain *mdp, int64_t *x)
498 {
499 int64_t v;
500 int error;
501
502 error = md_get_int64(mdp, &v);
503 *x = be64toh(v);
504 return error;
505 }
506
507 int
508 md_get_int64le(struct mdchain *mdp, int64_t *x)
509 {
510 int64_t v;
511 int error;
512
513 error = md_get_int64(mdp, &v);
514 *x = le64toh(v);
515 return error;
516 }
517
518 int
519 md_get_mem(struct mdchain *mdp, caddr_t target, size_t size, int type)
520 {
521 struct mbuf *m = mdp->md_cur;
522 int error;
523 size_t count;
524 u_char *s;
525
526 while (size > 0) {
527 if (m == NULL) {
528 #ifdef MCHAIN_DEBUG
529 MBERROR("incomplete copy\n");
530 #endif
531 return EBADRPC;
532 }
533 s = mdp->md_pos;
534 count = mtod(m, u_char*) + m->m_len - s;
535 if (count == 0) {
536 mdp->md_cur = m = m->m_next;
537 if (m)
538 s = mdp->md_pos = mtod(m, caddr_t);
539 continue;
540 }
541 if (count > size)
542 count = size;
543 size -= count;
544 mdp->md_pos += count;
545 if (target == NULL)
546 continue;
547 switch (type) {
548 case MB_MUSER:
549 error = copyout(s, target, count);
550 if (error)
551 return error;
552 break;
553 case MB_MSYSTEM:
554 bcopy(s, target, count);
555 break;
556 case MB_MINLINE:
557 while (count--)
558 *target++ = *s++;
559 continue;
560 }
561 target += count;
562 }
563 return 0;
564 }
565
566 int
567 md_get_mbuf(struct mdchain *mdp, int size, struct mbuf **ret)
568 {
569 struct mbuf *m = mdp->md_cur, *rm;
570
571 rm = m_copym(m, mdp->md_pos - mtod(m, u_char*), size, M_WAIT);
572 if (rm == NULL)
573 return EBADRPC;
574 md_get_mem(mdp, NULL, size, MB_MZERO);
575 *ret = rm;
576 return 0;
577 }
578
579 int
580 md_get_uio(struct mdchain *mdp, struct uio *uiop, size_t size)
581 {
582 char *uiocp;
583 size_t left;
584 int mtype, error;
585
586 mtype = VMSPACE_IS_KERNEL_P(uiop->uio_vmspace) ? MB_MSYSTEM : MB_MUSER;
587 while (size > 0 && uiop->uio_resid) {
588 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
589 return EFBIG;
590 left = uiop->uio_iov->iov_len;
591 if (left == 0) {
592 uiop->uio_iov++;
593 uiop->uio_iovcnt--;
594 continue;
595 }
596 uiocp = uiop->uio_iov->iov_base;
597 if (left > size)
598 left = size;
599 error = md_get_mem(mdp, uiocp, left, mtype);
600 if (error)
601 return error;
602 uiop->uio_offset += left;
603 uiop->uio_resid -= left;
604 uiop->uio_iov->iov_base =
605 (char *)uiop->uio_iov->iov_base + left;
606 uiop->uio_iov->iov_len -= left;
607 size -= left;
608 }
609 return 0;
610 }
Cache object: 20de9cd0d0a9493c7733f62e0b226adc
|