1 /* $NetBSD: subr_mchain.c,v 1.15.6.1 2010/07/16 18:47:10 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.15.6.1 2010/07/16 18:47:10 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(x) aprint_error x
51 #define MBPANIC(x) aprint_error x
52
53 #ifdef __NetBSD__
54 static struct mbuf *
55 m_getm(struct mbuf *m, size_t len, int how, int type)
56 {
57 struct mbuf *top, *tail, *mp, *mtail = NULL;
58
59 mp = m_get(how, type);
60 if (mp == NULL)
61 return (NULL);
62 else if (len > MINCLSIZE) {
63 m_clget(mp, how);
64 if ((mp->m_flags & M_EXT) == 0) {
65 m_free(mp);
66 return (NULL);
67 }
68 }
69 mp->m_len = 0;
70 len -= M_TRAILINGSPACE(mp);
71
72 if (m != NULL)
73 for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next);
74 else
75 m = mp;
76
77 top = tail = mp;
78 while (len > 0) {
79 mp = m_get(how, type);
80 if (mp == NULL)
81 goto failed;
82
83 tail->m_next = mp;
84 tail = mp;
85 if (len > MINCLSIZE) {
86 m_clget(mp, how);
87 if ((mp->m_flags & M_EXT) == 0)
88 goto failed;
89 }
90
91 mp->m_len = 0;
92 len -= M_TRAILINGSPACE(mp);
93 }
94
95 if (mtail != NULL)
96 mtail->m_next = top;
97 return (m);
98
99 failed:
100 m_freem(top);
101 return (NULL);
102 }
103
104 #endif /* __NetBSD__ */
105
106 /*
107 * Various helper functions
108 */
109 int
110 m_fixhdr(struct mbuf *m0)
111 {
112 struct mbuf *m = m0;
113 size_t len = 0;
114
115 while (m) {
116 len += m->m_len;
117 m = m->m_next;
118 }
119 m0->m_pkthdr.len = len;
120 return len;
121 }
122
123 int
124 mb_init(struct mbchain *mbp)
125 {
126 struct mbuf *m;
127
128 m = m_gethdr(M_WAIT, MT_DATA);
129 if (m == NULL)
130 return ENOBUFS;
131 m->m_len = 0;
132 mb_initm(mbp, m);
133 return 0;
134 }
135
136 void
137 mb_initm(struct mbchain *mbp, struct mbuf *m)
138 {
139 bzero(mbp, sizeof(*mbp));
140 mbp->mb_top = mbp->mb_cur = m;
141 mbp->mb_mleft = M_TRAILINGSPACE(m);
142 }
143
144 void
145 mb_done(struct mbchain *mbp)
146 {
147 if (mbp->mb_top) {
148 m_freem(mbp->mb_top);
149 mbp->mb_top = NULL;
150 }
151 }
152
153 struct mbuf *
154 mb_detach(struct mbchain *mbp)
155 {
156 struct mbuf *m;
157
158 m = mbp->mb_top;
159 mbp->mb_top = NULL;
160 return m;
161 }
162
163 int
164 mb_fixhdr(struct mbchain *mbp)
165 {
166 return mbp->mb_top->m_pkthdr.len = m_fixhdr(mbp->mb_top);
167 }
168
169 /*
170 * Check if object of size 'size' fit to the current position and
171 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
172 * Return pointer to the object placeholder or NULL if any error occurred.
173 * Note: size should be <= MLEN
174 */
175 void *
176 mb_reserve(struct mbchain *mbp, size_t size)
177 {
178 struct mbuf *m, *mn;
179 void *bpos;
180
181 if (size > MLEN)
182 panic("mb_reserve: size = %zu", size);
183 m = mbp->mb_cur;
184 if (mbp->mb_mleft < size) {
185 mn = m_get(M_WAIT, MT_DATA);
186 if (mn == NULL)
187 return NULL;
188 mbp->mb_cur = m->m_next = mn;
189 m = mn;
190 m->m_len = 0;
191 mbp->mb_mleft = M_TRAILINGSPACE(m);
192 }
193 mbp->mb_mleft -= size;
194 mbp->mb_count += size;
195 bpos = mtod(m, char *) + m->m_len;
196 m->m_len += size;
197 return bpos;
198 }
199
200 int
201 mb_put_uint8(struct mbchain *mbp, u_int8_t x)
202 {
203 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
204 }
205
206 int
207 mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
208 {
209 x = htobe16(x);
210 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
211 }
212
213 int
214 mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
215 {
216 x = htole16(x);
217 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
218 }
219
220 int
221 mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
222 {
223 x = htobe32(x);
224 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
225 }
226
227 int
228 mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
229 {
230 x = htole32(x);
231 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
232 }
233
234 int
235 mb_put_int64be(struct mbchain *mbp, int64_t x)
236 {
237 x = htobe64(x);
238 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
239 }
240
241 int
242 mb_put_int64le(struct mbchain *mbp, int64_t x)
243 {
244 x = htole64(x);
245 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
246 }
247
248 int
249 mb_put_mem(struct mbchain *mbp, const char *source, size_t size, int type)
250 {
251 struct mbuf *m;
252 char *dst;
253 const char *src;
254 int error;
255 size_t cplen, mleft, count;
256
257 m = mbp->mb_cur;
258 mleft = mbp->mb_mleft;
259
260 while (size > 0) {
261 if (mleft == 0) {
262 if (m->m_next == NULL) {
263 m = m_getm(m, size, M_WAIT, MT_DATA);
264 if (m == NULL)
265 return ENOBUFS;
266 }
267 m = m->m_next;
268 mleft = M_TRAILINGSPACE(m);
269 continue;
270 }
271 cplen = mleft > size ? size : mleft;
272 dst = mtod(m, char *) + m->m_len;
273 switch (type) {
274 case MB_MCUSTOM:
275 error = mbp->mb_copy(mbp, source, dst, cplen);
276 if (error)
277 return error;
278 break;
279 case MB_MINLINE:
280 for (src = source, count = cplen; count; count--)
281 *dst++ = *src++;
282 break;
283 case MB_MSYSTEM:
284 bcopy(source, dst, cplen);
285 break;
286 case MB_MUSER:
287 error = copyin(source, dst, cplen);
288 if (error)
289 return error;
290 break;
291 case MB_MZERO:
292 bzero(dst, cplen);
293 break;
294 }
295 size -= cplen;
296 source += cplen;
297 m->m_len += cplen;
298 mleft -= cplen;
299 mbp->mb_count += cplen;
300 }
301 mbp->mb_cur = m;
302 mbp->mb_mleft = mleft;
303 return 0;
304 }
305
306 int
307 mb_put_mbuf(struct mbchain *mbp, struct mbuf *m)
308 {
309 mbp->mb_cur->m_next = m;
310 while (m) {
311 mbp->mb_count += m->m_len;
312 if (m->m_next == NULL)
313 break;
314 m = m->m_next;
315 }
316 mbp->mb_mleft = M_TRAILINGSPACE(m);
317 mbp->mb_cur = m;
318 return 0;
319 }
320
321 /*
322 * copies a uio scatter/gather list to an mbuf chain.
323 */
324 int
325 mb_put_uio(struct mbchain *mbp, struct uio *uiop, size_t size)
326 {
327 size_t left;
328 int mtype, error;
329
330 mtype = VMSPACE_IS_KERNEL_P(uiop->uio_vmspace) ? MB_MSYSTEM : MB_MUSER;
331
332 while (size > 0 && uiop->uio_resid) {
333 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
334 return EFBIG;
335 left = uiop->uio_iov->iov_len;
336 if (left == 0) {
337 uiop->uio_iov++;
338 uiop->uio_iovcnt--;
339 continue;
340 }
341 if (left > size)
342 left = size;
343 error = mb_put_mem(mbp, uiop->uio_iov->iov_base, left, mtype);
344 if (error)
345 return error;
346 uiop->uio_offset += left;
347 uiop->uio_resid -= left;
348 uiop->uio_iov->iov_base =
349 (char *)uiop->uio_iov->iov_base + left;
350 uiop->uio_iov->iov_len -= left;
351 size -= left;
352 }
353 return 0;
354 }
355
356 /*
357 * Routines for fetching data from an mbuf chain
358 */
359 int
360 md_init(struct mdchain *mdp)
361 {
362 struct mbuf *m;
363
364 m = m_gethdr(M_WAIT, MT_DATA);
365 if (m == NULL)
366 return ENOBUFS;
367 m->m_len = 0;
368 md_initm(mdp, m);
369 return 0;
370 }
371
372 void
373 md_initm(struct mdchain *mdp, struct mbuf *m)
374 {
375 bzero(mdp, sizeof(*mdp));
376 mdp->md_top = mdp->md_cur = m;
377 mdp->md_pos = mtod(m, u_char*);
378 }
379
380 void
381 md_done(struct mdchain *mdp)
382 {
383 if (mdp->md_top) {
384 m_freem(mdp->md_top);
385 mdp->md_top = NULL;
386 }
387 }
388
389 /*
390 * Append a separate mbuf chain. It is caller responsibility to prevent
391 * multiple calls to fetch/record routines.
392 */
393 void
394 md_append_record(struct mdchain *mdp, struct mbuf *top)
395 {
396 struct mbuf *m;
397
398 if (mdp->md_top == NULL) {
399 md_initm(mdp, top);
400 return;
401 }
402 m = mdp->md_top;
403 while (m->m_nextpkt)
404 m = m->m_nextpkt;
405 m->m_nextpkt = top;
406 top->m_nextpkt = NULL;
407 return;
408 }
409
410 /*
411 * Put next record in place of existing
412 */
413 int
414 md_next_record(struct mdchain *mdp)
415 {
416 struct mbuf *m;
417
418 if (mdp->md_top == NULL)
419 return ENOENT;
420 m = mdp->md_top->m_nextpkt;
421 md_done(mdp);
422 if (m == NULL)
423 return ENOENT;
424 md_initm(mdp, m);
425 return 0;
426 }
427
428 int
429 md_get_uint8(struct mdchain *mdp, u_int8_t *x)
430 {
431 return md_get_mem(mdp, x, 1, MB_MINLINE);
432 }
433
434 int
435 md_get_uint16(struct mdchain *mdp, u_int16_t *x)
436 {
437 return md_get_mem(mdp, (void *)x, 2, MB_MINLINE);
438 }
439
440 int
441 md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
442 {
443 u_int16_t v;
444 int error = md_get_uint16(mdp, &v);
445
446 *x = le16toh(v);
447 return error;
448 }
449
450 int
451 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
452 u_int16_t v;
453 int error = md_get_uint16(mdp, &v);
454
455 *x = be16toh(v);
456 return error;
457 }
458
459 int
460 md_get_uint32(struct mdchain *mdp, u_int32_t *x)
461 {
462 return md_get_mem(mdp, (void *)x, 4, MB_MINLINE);
463 }
464
465 int
466 md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
467 {
468 u_int32_t v;
469 int error;
470
471 error = md_get_uint32(mdp, &v);
472 *x = be32toh(v);
473 return error;
474 }
475
476 int
477 md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
478 {
479 u_int32_t v;
480 int error;
481
482 error = md_get_uint32(mdp, &v);
483 *x = le32toh(v);
484 return error;
485 }
486
487 int
488 md_get_int64(struct mdchain *mdp, int64_t *x)
489 {
490 return md_get_mem(mdp, (void *)x, 8, MB_MINLINE);
491 }
492
493 int
494 md_get_int64be(struct mdchain *mdp, int64_t *x)
495 {
496 int64_t v;
497 int error;
498
499 error = md_get_int64(mdp, &v);
500 *x = be64toh(v);
501 return error;
502 }
503
504 int
505 md_get_int64le(struct mdchain *mdp, int64_t *x)
506 {
507 int64_t v;
508 int error;
509
510 error = md_get_int64(mdp, &v);
511 *x = le64toh(v);
512 return error;
513 }
514
515 int
516 md_get_mem(struct mdchain *mdp, void *targetv, size_t size, int type)
517 {
518 char *target = targetv;
519 struct mbuf *m = mdp->md_cur;
520 int error;
521 size_t count;
522 u_char *s;
523
524 while (size > 0) {
525 if (m == NULL) {
526 #ifdef MCHAIN_DEBUG
527 MBERROR(("incomplete copy\n"));
528 #endif
529 return EBADRPC;
530 }
531 s = mdp->md_pos;
532 count = mtod(m, u_char*) + m->m_len - s;
533 if (count == 0) {
534 mdp->md_cur = m = m->m_next;
535 if (m)
536 s = mdp->md_pos = mtod(m, void *);
537 continue;
538 }
539 if (count > size)
540 count = size;
541 size -= count;
542 mdp->md_pos += count;
543 if (target == NULL)
544 continue;
545 switch (type) {
546 case MB_MUSER:
547 error = copyout(s, target, count);
548 if (error)
549 return error;
550 break;
551 case MB_MSYSTEM:
552 bcopy(s, target, count);
553 break;
554 case MB_MINLINE:
555 while (count--)
556 *target++ = *s++;
557 continue;
558 }
559 target += count;
560 }
561 return 0;
562 }
563
564 int
565 md_get_mbuf(struct mdchain *mdp, int size, struct mbuf **ret)
566 {
567 struct mbuf *m = mdp->md_cur, *rm;
568
569 rm = m_copym(m, mdp->md_pos - mtod(m, u_char*), size, M_WAIT);
570 if (rm == NULL)
571 return EBADRPC;
572 md_get_mem(mdp, NULL, size, MB_MZERO);
573 *ret = rm;
574 return 0;
575 }
576
577 int
578 md_get_uio(struct mdchain *mdp, struct uio *uiop, size_t size)
579 {
580 char *uiocp;
581 size_t left;
582 int mtype, error;
583
584 mtype = VMSPACE_IS_KERNEL_P(uiop->uio_vmspace) ? MB_MSYSTEM : MB_MUSER;
585 while (size > 0 && uiop->uio_resid) {
586 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
587 return EFBIG;
588 left = uiop->uio_iov->iov_len;
589 if (left == 0) {
590 uiop->uio_iov++;
591 uiop->uio_iovcnt--;
592 continue;
593 }
594 uiocp = uiop->uio_iov->iov_base;
595 if (left > size)
596 left = size;
597 error = md_get_mem(mdp, uiocp, left, mtype);
598 if (error)
599 return error;
600 uiop->uio_offset += left;
601 uiop->uio_resid -= left;
602 uiop->uio_iov->iov_base =
603 (char *)uiop->uio_iov->iov_base + left;
604 uiop->uio_iov->iov_len -= left;
605 size -= left;
606 }
607 return 0;
608 }
Cache object: 9298cf69e92a73df67eaf179e15686da
|