2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Hartmut Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * In-kernel UNI stack message functions.
31 * $FreeBSD: src/sys/netgraph/atm/ngatmbase.c,v 1.3 2005/01/07 01:45:40 imp Exp $
34 #include <sys/param.h>
35 #include <sys/module.h>
36 #include <sys/kernel.h>
37 #include <sys/malloc.h>
38 #include <sys/systm.h>
40 #include <sys/mutex.h>
42 #include <machine/stdarg.h>
43 #include <netnatm/unimsg.h>
44 #include "atm/ngatmbase.h"
46 #define NGATMBASE_VERSION 1
48 static int ngatm_handler(module_t, int, void *);
50 static moduledata_t ngatm_data = {
56 MODULE_VERSION(ngatmbase, NGATMBASE_VERSION);
57 DECLARE_MODULE(ngatmbase, ngatm_data, SI_SUB_EXEC, SI_ORDER_ANY);
59 /*********************************************************************/
61 * UNI Stack message handling functions
63 MALLOC_DEFINE(M_UNIMSG, "unimsg", "uni message buffers");
64 MALLOC_DEFINE(M_UNIMSGHDR, "unimsghdr", "uni message headers");
68 /* mutex to protect the free list (and the used list if debugging) */
69 static struct mtx ngatm_unilist_mtx;
72 * Initialize UNI message subsystem
77 mtx_init(&ngatm_unilist_mtx, "netgraph UNI msg header lists", NULL,
82 * Ensure, that the message can be extended by at least s bytes.
83 * Re-allocate the message (not the header). If that failes,
84 * free the entire message and return ENOMEM. Free space at the start of
85 * the message is retained.
88 uni_msg_extend(struct uni_msg *m, size_t s)
93 lead = uni_msg_leading(m);
95 s += lead + len + EXTRA;
96 if ((b = kmalloc(s, M_UNIMSG, M_NOWAIT)) == NULL) {
101 bcopy(m->b_rptr, b + lead, len);
102 kfree(m->b_buf, M_UNIMSG);
105 m->b_rptr = m->b_buf + lead;
106 m->b_wptr = m->b_rptr + len;
107 m->b_lim = m->b_buf + s;
113 * Append a buffer to the message, making space if needed.
114 * If reallocation files, ENOMEM is returned and the message freed.
117 uni_msg_append(struct uni_msg *m, void *buf, size_t size)
121 if ((error = uni_msg_ensure(m, size)))
123 bcopy(buf, m->b_wptr, size);
130 * Pack/unpack data from/into mbufs. Assume, that the (optional) header
131 * fits into the first mbuf, ie. hdrlen < MHLEN. Note, that the message
132 * can be NULL, but hdrlen should not be 0 in this case.
135 uni_msg_pack_mbuf(struct uni_msg *msg, void *hdr, size_t hdrlen)
137 struct mbuf *m, *m0, *last;
140 MGETHDR(m0, MB_DONTWAIT, MT_DATA);
144 KASSERT(hdrlen <= MHLEN, ("uni_msg_pack_mbuf: hdrlen > MHLEN"));
147 bcopy(hdr, m0->m_data, hdrlen);
149 m0->m_pkthdr.len = hdrlen;
152 if ((n = uni_msg_len(msg)) > MHLEN) {
153 MCLGET(m0, MB_DONTWAIT);
154 if (!(m0->m_flags & M_EXT))
160 bcopy(msg->b_rptr, m0->m_data, n);
163 m0->m_pkthdr.len = n;
167 while (msg != NULL && (n = uni_msg_len(msg)) != 0) {
168 MGET(m, MB_DONTWAIT, MT_DATA);
175 MCLGET(m, MB_DONTWAIT);
176 if (!(m->m_flags & M_EXT))
182 bcopy(msg->b_rptr, m->m_data, n);
185 m0->m_pkthdr.len += n;
198 * Prepend a debugging header to each message
201 LIST_ENTRY(ngatm_msg) link;
208 * These are the lists of free and used message headers.
210 static LIST_HEAD(, ngatm_msg) ngatm_freeuni =
211 LIST_HEAD_INITIALIZER(ngatm_freeuni);
212 static LIST_HEAD(, ngatm_msg) ngatm_useduni =
213 LIST_HEAD_INITIALIZER(ngatm_useduni);
216 * Clean-up UNI message subsystem
223 /* free all free message headers */
224 while ((h = LIST_FIRST(&ngatm_freeuni)) != NULL) {
225 LIST_REMOVE(h, link);
226 kfree(h, M_UNIMSGHDR);
229 /* forget about still used messages */
230 LIST_FOREACH(h, &ngatm_useduni, link)
231 printf("unimsg header in use: %p (%s, %d)\n",
232 &h->msg, h->file, h->line);
234 mtx_destroy(&ngatm_unilist_mtx);
238 * Allocate a message, that can hold at least s bytes.
241 _uni_msg_alloc(size_t s, const char *file, int line)
245 mtx_lock(&ngatm_unilist_mtx);
246 if ((m = LIST_FIRST(&ngatm_freeuni)) != NULL)
247 LIST_REMOVE(m, link);
248 mtx_unlock(&ngatm_unilist_mtx);
251 (m = kmalloc(sizeof(*m), M_UNIMSGHDR, M_WAITOK | M_NULLOK)) == NULL)
255 if((m->msg.b_buf = kmalloc(s, M_UNIMSG, M_WAITOK | M_NULLOK | M_ZERO)) == NULL) {
256 mtx_lock(&ngatm_unilist_mtx);
257 LIST_INSERT_HEAD(&ngatm_freeuni, m, link);
258 mtx_unlock(&ngatm_unilist_mtx);
261 m->msg.b_rptr = m->msg.b_wptr = m->msg.b_buf;
262 m->msg.b_lim = m->msg.b_buf + s;
266 mtx_lock(&ngatm_unilist_mtx);
267 LIST_INSERT_HEAD(&ngatm_useduni, m, link);
268 mtx_unlock(&ngatm_unilist_mtx);
273 * Destroy a UNI message.
274 * The header is inserted into the free header list.
277 _uni_msg_destroy(struct uni_msg *m, const char *file, int line)
279 struct ngatm_msg *h, *d;
281 d = (struct ngatm_msg *)((char *)m - offsetof(struct ngatm_msg, msg));
283 mtx_lock(&ngatm_unilist_mtx);
284 LIST_FOREACH(h, &ngatm_useduni, link)
290 * Not on used list. Ups.
292 LIST_FOREACH(h, &ngatm_freeuni, link)
297 printf("uni_msg %p was never allocated; found "
298 "in %s:%u\n", m, file, line);
300 printf("uni_msg %p was already destroyed in %s,%d; "
301 "found in %s:%u\n", m, h->file, h->line,
304 kfree(m->b_buf, M_UNIMSG);
306 LIST_REMOVE(d, link);
307 LIST_INSERT_HEAD(&ngatm_freeuni, d, link);
313 mtx_unlock(&ngatm_unilist_mtx);
316 #else /* !NGATM_DEBUG */
319 * This assumes, that sizeof(struct uni_msg) >= sizeof(struct ngatm_msg)
320 * and the alignment requirements of are the same.
323 LIST_ENTRY(ngatm_msg) link;
326 /* Lists of free message headers. */
327 static LIST_HEAD(, ngatm_msg) ngatm_freeuni =
328 LIST_HEAD_INITIALIZER(ngatm_freeuni);
331 * Clean-up UNI message subsystem
338 /* free all free message headers */
339 while ((h = LIST_FIRST(&ngatm_freeuni)) != NULL) {
340 LIST_REMOVE(h, link);
341 kfree(h, M_UNIMSGHDR);
344 mtx_destroy(&ngatm_unilist_mtx);
348 * Allocate a message, that can hold at least s bytes.
351 uni_msg_alloc(size_t s)
356 mtx_lock(&ngatm_unilist_mtx);
357 if ((a = LIST_FIRST(&ngatm_freeuni)) != NULL)
358 LIST_REMOVE(a, link);
359 mtx_unlock(&ngatm_unilist_mtx);
362 if ((m = kmalloc(sizeof(*m), M_UNIMSGHDR, M_WAITOK | M_NULLOK)) == NULL)
364 a = (struct ngatm_msg *)m;
366 m = (struct uni_msg *)a;
369 if((m->b_buf = kmalloc(s, M_UNIMSG, M_WAITOK | M_NULLOK | M_ZERO)) == NULL) {
370 mtx_lock(&ngatm_unilist_mtx);
371 LIST_INSERT_HEAD(&ngatm_freeuni, a, link);
372 mtx_unlock(&ngatm_unilist_mtx);
375 m->b_rptr = m->b_wptr = m->b_buf;
376 m->b_lim = m->b_buf + s;
382 * Destroy a UNI message.
383 * The header is inserted into the free header list.
386 uni_msg_destroy(struct uni_msg *m)
390 a = (struct ngatm_msg *)m;
392 kfree(m->b_buf, M_UNIMSG);
394 mtx_lock(&ngatm_unilist_mtx);
395 LIST_INSERT_HEAD(&ngatm_freeuni, a, link);
396 mtx_unlock(&ngatm_unilist_mtx);
402 * Build a message from a number of buffers. Arguments are pairs
403 * of (void *, size_t) ending with a NULL pointer.
407 _uni_msg_build(const char *file, int line, void *ptr, ...)
410 uni_msg_build(void *ptr, ...)
422 n = va_arg(ap, size_t);
424 p1 = va_arg(ap, void *);
429 if ((m = _uni_msg_alloc(len, file, line)) == NULL)
431 if ((m = uni_msg_alloc(len)) == NULL)
438 n = va_arg(ap, size_t);
439 bcopy(p1, m->b_wptr, n);
441 p1 = va_arg(ap, void *);
449 * Unpack an mbuf chain into a uni_msg buffer.
453 _uni_msg_unpack_mbuf(struct mbuf *m, struct uni_msg **pmsg, const char *file,
457 uni_msg_unpack_mbuf(struct mbuf *m, struct uni_msg **pmsg)
460 if (!(m->m_flags & M_PKTHDR)) {
461 printf("%s: bogus packet %p\n", __func__, m);
465 if ((*pmsg = _uni_msg_alloc(m->m_pkthdr.len, file, line)) == NULL)
467 if ((*pmsg = uni_msg_alloc(m->m_pkthdr.len)) == NULL)
471 m_copydata(m, 0, m->m_pkthdr.len, (*pmsg)->b_wptr);
472 (*pmsg)->b_wptr += m->m_pkthdr.len;
477 /*********************************************************************/
480 ngatm_handler(module_t mod, int what, void *arg)