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.
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD: src/sys/netgraph/atm/ngatmbase.c,v 1.3 2005/01/07 01:45:40 imp Exp $");
35 #include <sys/param.h>
36 #include <sys/module.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <sys/systm.h>
41 #include <sys/mutex.h>
43 #include <machine/stdarg.h>
44 #include <netnatm/unimsg.h>
45 #include <netgraph/atm/ngatmbase.h>
47 #define NGATMBASE_VERSION 1
49 static int ngatm_handler(module_t
, int, void *);
51 static moduledata_t ngatm_data
= {
57 MODULE_VERSION(ngatmbase
, NGATMBASE_VERSION
);
58 DECLARE_MODULE(ngatmbase
, ngatm_data
, SI_SUB_EXEC
, SI_ORDER_ANY
);
60 /*********************************************************************/
62 * UNI Stack message handling functions
64 MALLOC_DEFINE(M_UNIMSG
, "unimsg", "uni message buffers");
65 MALLOC_DEFINE(M_UNIMSGHDR
, "unimsghdr", "uni message headers");
69 /* mutex to protect the free list (and the used list if debugging) */
70 static struct mtx ngatm_unilist_mtx
;
73 * Initialize UNI message subsystem
78 mtx_init(&ngatm_unilist_mtx
, "netgraph UNI msg header lists", NULL
,
83 * Ensure, that the message can be extended by at least s bytes.
84 * Re-allocate the message (not the header). If that failes,
85 * free the entire message and return ENOMEM. Free space at the start of
86 * the message is retained.
89 uni_msg_extend(struct uni_msg
*m
, size_t s
)
94 lead
= uni_msg_leading(m
);
96 s
+= lead
+ len
+ EXTRA
;
97 if ((b
= malloc(s
, M_UNIMSG
, M_NOWAIT
)) == NULL
) {
102 bcopy(m
->b_rptr
, b
+ lead
, len
);
103 free(m
->b_buf
, M_UNIMSG
);
106 m
->b_rptr
= m
->b_buf
+ lead
;
107 m
->b_wptr
= m
->b_rptr
+ len
;
108 m
->b_lim
= m
->b_buf
+ s
;
114 * Append a buffer to the message, making space if needed.
115 * If reallocation files, ENOMEM is returned and the message freed.
118 uni_msg_append(struct uni_msg
*m
, void *buf
, size_t size
)
122 if ((error
= uni_msg_ensure(m
, size
)))
124 bcopy(buf
, m
->b_wptr
, size
);
131 * Pack/unpack data from/into mbufs. Assume, that the (optional) header
132 * fits into the first mbuf, ie. hdrlen < MHLEN. Note, that the message
133 * can be NULL, but hdrlen should not be 0 in this case.
136 uni_msg_pack_mbuf(struct uni_msg
*msg
, void *hdr
, size_t hdrlen
)
138 struct mbuf
*m
, *m0
, *last
;
141 MGETHDR(m0
, M_NOWAIT
, MT_DATA
);
145 KASSERT(hdrlen
<= MHLEN
, ("uni_msg_pack_mbuf: hdrlen > MHLEN"));
148 bcopy(hdr
, m0
->m_data
, hdrlen
);
150 m0
->m_pkthdr
.len
= hdrlen
;
153 if ((n
= uni_msg_len(msg
)) > MHLEN
) {
154 MCLGET(m0
, M_NOWAIT
);
155 if (!(m0
->m_flags
& M_EXT
))
161 bcopy(msg
->b_rptr
, m0
->m_data
, n
);
164 m0
->m_pkthdr
.len
= n
;
168 while (msg
!= NULL
&& (n
= uni_msg_len(msg
)) != 0) {
169 MGET(m
, M_NOWAIT
, MT_DATA
);
177 if (!(m
->m_flags
& M_EXT
))
183 bcopy(msg
->b_rptr
, m
->m_data
, n
);
186 m0
->m_pkthdr
.len
+= n
;
199 * Prepend a debugging header to each message
202 LIST_ENTRY(ngatm_msg
) link
;
209 * These are the lists of free and used message headers.
211 static LIST_HEAD(, ngatm_msg
) ngatm_freeuni
=
212 LIST_HEAD_INITIALIZER(ngatm_freeuni
);
213 static LIST_HEAD(, ngatm_msg
) ngatm_useduni
=
214 LIST_HEAD_INITIALIZER(ngatm_useduni
);
217 * Clean-up UNI message subsystem
224 /* free all free message headers */
225 while ((h
= LIST_FIRST(&ngatm_freeuni
)) != NULL
) {
226 LIST_REMOVE(h
, link
);
227 free(h
, M_UNIMSGHDR
);
230 /* forget about still used messages */
231 LIST_FOREACH(h
, &ngatm_useduni
, link
)
232 printf("unimsg header in use: %p (%s, %d)\n",
233 &h
->msg
, h
->file
, h
->line
);
235 mtx_destroy(&ngatm_unilist_mtx
);
239 * Allocate a message, that can hold at least s bytes.
242 _uni_msg_alloc(size_t s
, const char *file
, int line
)
246 mtx_lock(&ngatm_unilist_mtx
);
247 if ((m
= LIST_FIRST(&ngatm_freeuni
)) != NULL
)
248 LIST_REMOVE(m
, link
);
249 mtx_unlock(&ngatm_unilist_mtx
);
252 (m
= malloc(sizeof(*m
), M_UNIMSGHDR
, M_NOWAIT
)) == NULL
)
256 if((m
->msg
.b_buf
= malloc(s
, M_UNIMSG
, M_NOWAIT
| M_ZERO
)) == NULL
) {
257 mtx_lock(&ngatm_unilist_mtx
);
258 LIST_INSERT_HEAD(&ngatm_freeuni
, m
, link
);
259 mtx_unlock(&ngatm_unilist_mtx
);
262 m
->msg
.b_rptr
= m
->msg
.b_wptr
= m
->msg
.b_buf
;
263 m
->msg
.b_lim
= m
->msg
.b_buf
+ s
;
267 mtx_lock(&ngatm_unilist_mtx
);
268 LIST_INSERT_HEAD(&ngatm_useduni
, m
, link
);
269 mtx_unlock(&ngatm_unilist_mtx
);
274 * Destroy a UNI message.
275 * The header is inserted into the free header list.
278 _uni_msg_destroy(struct uni_msg
*m
, const char *file
, int line
)
280 struct ngatm_msg
*h
, *d
;
282 d
= (struct ngatm_msg
*)((char *)m
- offsetof(struct ngatm_msg
, msg
));
284 mtx_lock(&ngatm_unilist_mtx
);
285 LIST_FOREACH(h
, &ngatm_useduni
, link
)
291 * Not on used list. Ups.
293 LIST_FOREACH(h
, &ngatm_freeuni
, link
)
298 printf("uni_msg %p was never allocated; found "
299 "in %s:%u\n", m
, file
, line
);
301 printf("uni_msg %p was already destroyed in %s,%d; "
302 "found in %s:%u\n", m
, h
->file
, h
->line
,
305 free(m
->b_buf
, M_UNIMSG
);
307 LIST_REMOVE(d
, link
);
308 LIST_INSERT_HEAD(&ngatm_freeuni
, d
, link
);
314 mtx_unlock(&ngatm_unilist_mtx
);
317 #else /* !NGATM_DEBUG */
320 * This assumes, that sizeof(struct uni_msg) >= sizeof(struct ngatm_msg)
321 * and the alignment requirements of are the same.
324 LIST_ENTRY(ngatm_msg
) link
;
327 /* Lists of free message headers. */
328 static LIST_HEAD(, ngatm_msg
) ngatm_freeuni
=
329 LIST_HEAD_INITIALIZER(ngatm_freeuni
);
332 * Clean-up UNI message subsystem
339 /* free all free message headers */
340 while ((h
= LIST_FIRST(&ngatm_freeuni
)) != NULL
) {
341 LIST_REMOVE(h
, link
);
342 free(h
, M_UNIMSGHDR
);
345 mtx_destroy(&ngatm_unilist_mtx
);
349 * Allocate a message, that can hold at least s bytes.
352 uni_msg_alloc(size_t s
)
357 mtx_lock(&ngatm_unilist_mtx
);
358 if ((a
= LIST_FIRST(&ngatm_freeuni
)) != NULL
)
359 LIST_REMOVE(a
, link
);
360 mtx_unlock(&ngatm_unilist_mtx
);
363 if ((m
= malloc(sizeof(*m
), M_UNIMSGHDR
, M_NOWAIT
)) == NULL
)
365 a
= (struct ngatm_msg
*)m
;
367 m
= (struct uni_msg
*)a
;
370 if((m
->b_buf
= malloc(s
, M_UNIMSG
, M_NOWAIT
| M_ZERO
)) == NULL
) {
371 mtx_lock(&ngatm_unilist_mtx
);
372 LIST_INSERT_HEAD(&ngatm_freeuni
, a
, link
);
373 mtx_unlock(&ngatm_unilist_mtx
);
376 m
->b_rptr
= m
->b_wptr
= m
->b_buf
;
377 m
->b_lim
= m
->b_buf
+ s
;
383 * Destroy a UNI message.
384 * The header is inserted into the free header list.
387 uni_msg_destroy(struct uni_msg
*m
)
391 a
= (struct ngatm_msg
*)m
;
393 free(m
->b_buf
, M_UNIMSG
);
395 mtx_lock(&ngatm_unilist_mtx
);
396 LIST_INSERT_HEAD(&ngatm_freeuni
, a
, link
);
397 mtx_unlock(&ngatm_unilist_mtx
);
403 * Build a message from a number of buffers. Arguments are pairs
404 * of (void *, size_t) ending with a NULL pointer.
408 _uni_msg_build(const char *file
, int line
, void *ptr
, ...)
411 uni_msg_build(void *ptr
, ...)
423 n
= va_arg(ap
, size_t);
425 p1
= va_arg(ap
, void *);
430 if ((m
= _uni_msg_alloc(len
, file
, line
)) == NULL
)
432 if ((m
= uni_msg_alloc(len
)) == NULL
)
439 n
= va_arg(ap
, size_t);
440 bcopy(p1
, m
->b_wptr
, n
);
442 p1
= va_arg(ap
, void *);
450 * Unpack an mbuf chain into a uni_msg buffer.
454 _uni_msg_unpack_mbuf(struct mbuf
*m
, struct uni_msg
**pmsg
, const char *file
,
458 uni_msg_unpack_mbuf(struct mbuf
*m
, struct uni_msg
**pmsg
)
461 if (!(m
->m_flags
& M_PKTHDR
)) {
462 printf("%s: bogus packet %p\n", __func__
, m
);
466 if ((*pmsg
= _uni_msg_alloc(m
->m_pkthdr
.len
, file
, line
)) == NULL
)
468 if ((*pmsg
= uni_msg_alloc(m
->m_pkthdr
.len
)) == NULL
)
472 m_copydata(m
, 0, m
->m_pkthdr
.len
, (*pmsg
)->b_wptr
);
473 (*pmsg
)->b_wptr
+= m
->m_pkthdr
.len
;
478 /*********************************************************************/
481 ngatm_handler(module_t mod
, int what
, void *arg
)