__P() removal
[dragonfly.git] / sys / kern / uipc_mbuf2.c
1 /*      $FreeBSD: src/sys/kern/uipc_mbuf2.c,v 1.2.2.5 2003/01/23 21:06:44 sam Exp $     */
2 /*      $DragonFly: src/sys/kern/uipc_mbuf2.c,v 1.4 2003/08/26 21:09:02 rob Exp $       */
3 /*      $KAME: uipc_mbuf2.c,v 1.31 2001/11/28 11:08:53 itojun Exp $     */
4 /*      $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $   */
5
6 /*
7  * Copyright (C) 1999 WIDE Project.
8  * All rights reserved.
9  * 
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the project nor the names of its 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 PROJECT 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 PROJECT 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
35 /*
36  * Copyright (c) 1982, 1986, 1988, 1991, 1993
37  *      The Regents of the University of California.  All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *      This product includes software developed by the University of
50  *      California, Berkeley and its contributors.
51  * 4. Neither the name of the University nor the names of its contributors
52  *    may be used to endorse or promote products derived from this software
53  *    without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  *
67  *      @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
68  */
69
70 /*#define PULLDOWN_DEBUG*/
71
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/kernel.h>
75 #include <sys/proc.h>
76 #include <sys/malloc.h>
77 #include <sys/mbuf.h>
78
79 #define M_SHAREDCLUSTER(m) \
80         (((m)->m_flags & M_EXT) != 0 && \
81          ((m)->m_ext.ext_free || mclrefcnt[mtocl((m)->m_ext.ext_buf)] > 1))
82
83 MALLOC_DEFINE(M_PACKET_TAGS, "tag", "packet-attached information");
84
85 /* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
86 static struct mbuf *m_dup1 (struct mbuf *, int, int, int);
87
88 /*
89  * ensure that [off, off + len) is contiguous on the mbuf chain "m".
90  * packet chain before "off" is kept untouched.
91  * if offp == NULL, the target will start at <retval, 0> on resulting chain.
92  * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
93  *
94  * on error return (NULL return value), original "m" will be freed.
95  *
96  * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
97  */
98 struct mbuf *
99 m_pulldown(m, off, len, offp)
100         struct mbuf *m;
101         int off, len;
102         int *offp;
103 {
104         struct mbuf *n, *o;
105         int hlen, tlen, olen;
106         int sharedcluster;
107
108         /* check invalid arguments. */
109         if (m == NULL)
110                 panic("m == NULL in m_pulldown()");
111         if (len > MCLBYTES) {
112                 m_freem(m);
113                 return NULL;    /* impossible */
114         }
115
116 #ifdef PULLDOWN_DEBUG
117     {
118         struct mbuf *t;
119         printf("before:");
120         for (t = m; t; t = t->m_next)
121                 printf(" %d", t->m_len);
122         printf("\n");
123     }
124 #endif
125         n = m;
126         while (n != NULL && off > 0) {
127                 if (n->m_len > off)
128                         break;
129                 off -= n->m_len;
130                 n = n->m_next;
131         }
132         /* be sure to point non-empty mbuf */
133         while (n != NULL && n->m_len == 0)
134                 n = n->m_next;
135         if (!n) {
136                 m_freem(m);
137                 return NULL;    /* mbuf chain too short */
138         }
139
140         sharedcluster = M_SHAREDCLUSTER(n);
141
142         /*
143          * the target data is on <n, off>.
144          * if we got enough data on the mbuf "n", we're done.
145          */
146         if ((off == 0 || offp) && len <= n->m_len - off && !sharedcluster)
147                 goto ok;
148
149         /*
150          * when len <= n->m_len - off and off != 0, it is a special case.
151          * len bytes from <n, off> sits in single mbuf, but the caller does
152          * not like the starting position (off).
153          * chop the current mbuf into two pieces, set off to 0.
154          */
155         if (len <= n->m_len - off) {
156                 o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
157                 if (o == NULL) {
158                         m_freem(m);
159                         return NULL;    /* ENOBUFS */
160                 }
161                 n->m_len = off;
162                 o->m_next = n->m_next;
163                 n->m_next = o;
164                 n = n->m_next;
165                 off = 0;
166                 goto ok;
167         }
168
169         /*
170          * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
171          * and construct contiguous mbuf with m_len == len.
172          * note that hlen + tlen == len, and tlen > 0.
173          */
174         hlen = n->m_len - off;
175         tlen = len - hlen;
176
177         /*
178          * ensure that we have enough trailing data on mbuf chain.
179          * if not, we can do nothing about the chain.
180          */
181         olen = 0;
182         for (o = n->m_next; o != NULL; o = o->m_next)
183                 olen += o->m_len;
184         if (hlen + olen < len) {
185                 m_freem(m);
186                 return NULL;    /* mbuf chain too short */
187         }
188
189         /*
190          * easy cases first.
191          * we need to use m_copydata() to get data from <n->m_next, 0>.
192          */
193         if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen &&
194             !sharedcluster) {
195                 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
196                 n->m_len += tlen;
197                 m_adj(n->m_next, tlen);
198                 goto ok;
199         }
200         if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen &&
201             !sharedcluster) {
202                 n->m_next->m_data -= hlen;
203                 n->m_next->m_len += hlen;
204                 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
205                 n->m_len -= hlen;
206                 n = n->m_next;
207                 off = 0;
208                 goto ok;
209         }
210
211         /*
212          * now, we need to do the hard way.  don't m_copy as there's no room
213          * on both end.
214          */
215         MGET(o, M_DONTWAIT, m->m_type);
216         if (o && len > MLEN) {
217                 MCLGET(o, M_DONTWAIT);
218                 if ((o->m_flags & M_EXT) == 0) {
219                         m_free(o);
220                         o = NULL;
221                 }
222         }
223         if (!o) {
224                 m_freem(m);
225                 return NULL;    /* ENOBUFS */
226         }
227         /* get hlen from <n, off> into <o, 0> */
228         o->m_len = hlen;
229         bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
230         n->m_len -= hlen;
231         /* get tlen from <n->m_next, 0> into <o, hlen> */
232         m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
233         o->m_len += tlen;
234         m_adj(n->m_next, tlen);
235         o->m_next = n->m_next;
236         n->m_next = o;
237         n = o;
238         off = 0;
239
240 ok:
241 #ifdef PULLDOWN_DEBUG
242     {
243         struct mbuf *t;
244         printf("after:");
245         for (t = m; t; t = t->m_next)
246                 printf("%c%d", t == n ? '*' : ' ', t->m_len);
247         printf(" (off=%d)\n", off);
248     }
249 #endif
250         if (offp)
251                 *offp = off;
252         return n;
253 }
254
255 static struct mbuf *
256 m_dup1(m, off, len, wait)
257         struct mbuf *m;
258         int off;
259         int len;
260         int wait;
261 {
262         struct mbuf *n;
263         int l;
264         int copyhdr;
265
266         if (len > MCLBYTES)
267                 return NULL;
268         if (off == 0 && (m->m_flags & M_PKTHDR) != 0) {
269                 copyhdr = 1;
270                 MGETHDR(n, wait, m->m_type);
271                 l = MHLEN;
272         } else {
273                 copyhdr = 0;
274                 MGET(n, wait, m->m_type);
275                 l = MLEN;
276         }
277         if (n && len > l) {
278                 MCLGET(n, wait);
279                 if ((n->m_flags & M_EXT) == 0) {
280                         m_free(n);
281                         n = NULL;
282                 }
283         }
284         if (!n)
285                 return NULL;
286
287         if (copyhdr && !m_dup_pkthdr(n, m, wait)) {
288                 m_free(n);
289                 return NULL;
290         }
291         m_copydata(m, off, len, mtod(n, caddr_t));
292         return n;
293 }
294
295 /* Get a packet tag structure along with specified data following. */
296 struct m_tag *
297 m_tag_alloc(u_int32_t cookie, int type, int len, int wait)
298 {
299         struct m_tag *t;
300
301         if (len < 0)
302                 return NULL;
303         t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
304         if (t == NULL)
305                 return NULL;
306         t->m_tag_id = type;
307         t->m_tag_len = len;
308         t->m_tag_cookie = cookie;
309         return t;
310 }
311
312
313 /* Free a packet tag. */
314 void
315 m_tag_free(struct m_tag *t)
316 {
317         free(t, M_PACKET_TAGS);
318 }
319
320 /* Prepend a packet tag. */
321 void
322 m_tag_prepend(struct mbuf *m, struct m_tag *t)
323 {
324         KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
325         SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
326 }
327
328 /* Unlink a packet tag. */
329 void
330 m_tag_unlink(struct mbuf *m, struct m_tag *t)
331 {
332         KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
333         SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
334 }
335
336 /* Unlink and free a packet tag. */
337 void
338 m_tag_delete(struct mbuf *m, struct m_tag *t)
339 {
340         KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
341         m_tag_unlink(m, t);
342         m_tag_free(t);
343 }
344
345 /* Unlink and free a packet tag chain, starting from given tag. */
346 void
347 m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
348 {
349         struct m_tag *p, *q;
350
351         KASSERT(m, ("m_tag_delete_chain: null mbuf"));
352         if (t != NULL)
353                 p = t;
354         else
355                 p = SLIST_FIRST(&m->m_pkthdr.tags);
356         if (p == NULL)
357                 return;
358         while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
359                 m_tag_delete(m, q);
360         m_tag_delete(m, p);
361 }
362
363 /* Find a tag, starting from a given position. */
364 struct m_tag *
365 m_tag_locate(struct mbuf *m, u_int32_t cookie, int type, struct m_tag *t)
366 {
367         struct m_tag *p;
368
369         KASSERT(m, ("m_tag_find: null mbuf"));
370         if (t == NULL)
371                 p = SLIST_FIRST(&m->m_pkthdr.tags);
372         else
373                 p = SLIST_NEXT(t, m_tag_link);
374         while (p != NULL) {
375                 if (p->m_tag_cookie == cookie && p->m_tag_id == type)
376                         return p;
377                 p = SLIST_NEXT(p, m_tag_link);
378         }
379         return NULL;
380 }
381
382 /* Copy a single tag. */
383 struct m_tag *
384 m_tag_copy(struct m_tag *t, int how)
385 {
386         struct m_tag *p;
387
388         KASSERT(t, ("m_tag_copy: null tag"));
389         p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how);
390         if (p == NULL)
391                 return (NULL);
392         bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
393         return p;
394 }
395
396 /*
397  * Copy two tag chains. The destination mbuf (to) loses any attached
398  * tags even if the operation fails. This should not be a problem, as
399  * m_tag_copy_chain() is typically called with a newly-allocated
400  * destination mbuf.
401  */
402 int
403 m_tag_copy_chain(struct mbuf *to, const struct mbuf *from, int how)
404 {
405         struct m_tag *p, *t, *tprev = NULL;
406
407         KASSERT(to && from,
408                 ("m_tag_copy: null argument, to %p from %p", to, from));
409         m_tag_delete_chain(to, NULL);
410         SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
411                 t = m_tag_copy(p, how);
412                 if (t == NULL) {
413                         m_tag_delete_chain(to, NULL);
414                         return 0;
415                 }
416                 if (tprev == NULL)
417                         SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
418                 else {
419                         SLIST_INSERT_AFTER(tprev, t, m_tag_link);
420                         tprev = t;
421                 }
422         }
423         return 1;
424 }
425
426 /* Initialize tags on an mbuf. */
427 void
428 m_tag_init(struct mbuf *m)
429 {
430         SLIST_INIT(&m->m_pkthdr.tags);
431 }
432
433 /* Get first tag in chain. */
434 struct m_tag *
435 m_tag_first(struct mbuf *m)
436 {
437         return SLIST_FIRST(&m->m_pkthdr.tags);
438 }
439
440 /* Get next tag in chain. */
441 struct m_tag *
442 m_tag_next(struct mbuf *m, struct m_tag *t)
443 {
444         return SLIST_NEXT(t, m_tag_link);
445 }