freebsd-dev/sys/netgraph/atm/uni/ng_uni.c
Robert Watson 5bb84bc84b Normalize a significant number of kernel malloc type names:
- Prefer '_' to ' ', as it results in more easily parsed results in
  memory monitoring tools such as vmstat.

- Remove punctuation that is incompatible with using memory type names
  as file names, such as '/' characters.

- Disambiguate some collisions by adding subsystem prefixes to some
  memory types.

- Generally prefer lower case to upper case.

- If the same type is defined in multiple architecture directories,
  attempt to use the same name in additional cases.

Not all instances were caught in this change, so more work is required to
finish this conversion.  Similar changes are required for UMA zone names.
2005-10-31 15:41:29 +00:00

932 lines
19 KiB
C

/*-
* Copyright (c) 2001-2003
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
* All rights reserved.
*
* Author: Hartmut Brandt <harti@freebsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Netgraph module for ATM-Forum UNI 4.0 signalling
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/errno.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/callout.h>
#include <sys/sbuf.h>
#include <machine/stdarg.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netnatm/unimsg.h>
#include <netnatm/msg/unistruct.h>
#include <netgraph/atm/ngatmbase.h>
#include <netnatm/saal/sscopdef.h>
#include <netnatm/saal/sscfudef.h>
#include <netgraph/atm/uni/ng_uni_cust.h>
#include <netnatm/sig/uni.h>
#include <netnatm/sig/unisig.h>
#include <netgraph/atm/ng_sscop.h>
#include <netgraph/atm/ng_sscfu.h>
#include <netgraph/atm/ng_uni.h>
MALLOC_DEFINE(M_NG_UNI, "netgraph_uni_node", "netgraph uni node");
MALLOC_DEFINE(M_UNI, "netgraph_uni_data", "uni protocol data");
MODULE_DEPEND(ng_uni, ngatmbase, 1, 1, 1);
/*
* Private node data
*/
struct priv {
hook_p upper;
hook_p lower;
struct uni *uni;
int enabled;
};
/* UNI CONFIG MASK */
static const struct ng_parse_struct_field ng_uni_config_mask_type_info[] =
NGM_UNI_CONFIG_MASK_INFO;
static const struct ng_parse_type ng_uni_config_mask_type = {
&ng_parse_struct_type,
ng_uni_config_mask_type_info
};
/* UNI_CONFIG */
static const struct ng_parse_struct_field ng_uni_config_type_info[] =
NGM_UNI_CONFIG_INFO;
static const struct ng_parse_type ng_uni_config_type = {
&ng_parse_struct_type,
ng_uni_config_type_info
};
/* SET CONFIG */
static const struct ng_parse_struct_field ng_uni_set_config_type_info[] =
NGM_UNI_SET_CONFIG_INFO;
static const struct ng_parse_type ng_uni_set_config_type = {
&ng_parse_struct_type,
ng_uni_set_config_type_info
};
/*
* Parse DEBUG
*/
static const struct ng_parse_fixedarray_info ng_uni_debuglevel_type_info =
NGM_UNI_DEBUGLEVEL_INFO;
static const struct ng_parse_type ng_uni_debuglevel_type = {
&ng_parse_fixedarray_type,
&ng_uni_debuglevel_type_info
};
static const struct ng_parse_struct_field ng_uni_debug_type_info[] =
NGM_UNI_DEBUG_INFO;
static const struct ng_parse_type ng_uni_debug_type = {
&ng_parse_struct_type,
ng_uni_debug_type_info
};
/*
* Command list
*/
static const struct ng_cmdlist ng_uni_cmdlist[] = {
{
NGM_UNI_COOKIE,
NGM_UNI_GETDEBUG,
"getdebug",
NULL,
&ng_uni_debug_type
},
{
NGM_UNI_COOKIE,
NGM_UNI_SETDEBUG,
"setdebug",
&ng_uni_debug_type,
NULL
},
{
NGM_UNI_COOKIE,
NGM_UNI_GET_CONFIG,
"get_config",
NULL,
&ng_uni_config_type
},
{
NGM_UNI_COOKIE,
NGM_UNI_SET_CONFIG,
"set_config",
&ng_uni_set_config_type,
&ng_uni_config_mask_type,
},
{
NGM_UNI_COOKIE,
NGM_UNI_ENABLE,
"enable",
NULL,
NULL,
},
{
NGM_UNI_COOKIE,
NGM_UNI_DISABLE,
"disable",
NULL,
NULL,
},
{
NGM_UNI_COOKIE,
NGM_UNI_GETSTATE,
"getstate",
NULL,
&ng_parse_uint32_type
},
{ 0 }
};
/*
* Netgraph module data
*/
static ng_constructor_t ng_uni_constructor;
static ng_shutdown_t ng_uni_shutdown;
static ng_rcvmsg_t ng_uni_rcvmsg;
static ng_newhook_t ng_uni_newhook;
static ng_disconnect_t ng_uni_disconnect;
static ng_rcvdata_t ng_uni_rcvlower;
static ng_rcvdata_t ng_uni_rcvupper;
static int ng_uni_mod_event(module_t, int, void *);
static struct ng_type ng_uni_typestruct = {
.version = NG_ABI_VERSION,
.name = NG_UNI_NODE_TYPE,
.mod_event = ng_uni_mod_event,
.constructor = ng_uni_constructor,
.rcvmsg = ng_uni_rcvmsg,
.shutdown = ng_uni_shutdown,
.newhook = ng_uni_newhook,
.rcvdata = ng_uni_rcvlower,
.disconnect = ng_uni_disconnect,
.cmdlist = ng_uni_cmdlist,
};
NETGRAPH_INIT(uni, &ng_uni_typestruct);
static void uni_uni_output(struct uni *, void *, enum uni_sig, u_int32_t,
struct uni_msg *);
static void uni_saal_output(struct uni *, void *, enum saal_sig,
struct uni_msg *);
static void uni_verbose(struct uni *, void *, u_int, const char *, ...)
__printflike(4, 5);
static void uni_do_status(struct uni *, void *, void *, const char *, ...)
__printflike(4, 5);
static const struct uni_funcs uni_funcs = {
uni_uni_output,
uni_saal_output,
uni_verbose,
uni_do_status
};
/************************************************************/
/*
* NODE MANAGEMENT
*/
static int
ng_uni_constructor(node_p node)
{
struct priv *priv;
if ((priv = malloc(sizeof(*priv), M_NG_UNI, M_NOWAIT | M_ZERO)) == NULL)
return (ENOMEM);
if ((priv->uni = uni_create(node, &uni_funcs)) == NULL) {
free(priv, M_NG_UNI);
return (ENOMEM);
}
NG_NODE_SET_PRIVATE(node, priv);
NG_NODE_FORCE_WRITER(node);
return (0);
}
static int
ng_uni_shutdown(node_p node)
{
struct priv *priv = NG_NODE_PRIVATE(node);
uni_destroy(priv->uni);
free(priv, M_NG_UNI);
NG_NODE_SET_PRIVATE(node, NULL);
NG_NODE_UNREF(node);
return (0);
}
/************************************************************/
/*
* CONTROL MESSAGES
*/
static void
uni_do_status(struct uni *uni, void *uarg, void *sbuf, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
sbuf_printf(sbuf, fmt, ap);
va_end(ap);
}
static int
text_status(node_p node, struct priv *priv, char *buf, u_int len)
{
struct sbuf sbuf;
u_int f;
sbuf_new(&sbuf, buf, len, 0);
if (priv->lower != NULL)
sbuf_printf(&sbuf, "lower hook: connected to %s:%s\n",
NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->lower))),
NG_HOOK_NAME(NG_HOOK_PEER(priv->lower)));
else
sbuf_printf(&sbuf, "lower hook: <not connected>\n");
if (priv->upper != NULL)
sbuf_printf(&sbuf, "upper hook: connected to %s:%s\n",
NG_NODE_NAME(NG_HOOK_NODE(NG_HOOK_PEER(priv->upper))),
NG_HOOK_NAME(NG_HOOK_PEER(priv->upper)));
else
sbuf_printf(&sbuf, "upper hook: <not connected>\n");
sbuf_printf(&sbuf, "debugging:");
for (f = 0; f < UNI_MAXFACILITY; f++)
if (uni_get_debug(priv->uni, f) != 0)
sbuf_printf(&sbuf, " %s=%u", uni_facname(f),
uni_get_debug(priv->uni, f));
sbuf_printf(&sbuf, "\n");
if (priv->uni)
uni_status(priv->uni, &sbuf);
sbuf_finish(&sbuf);
return (sbuf_len(&sbuf));
}
static int
ng_uni_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
struct priv *priv = NG_NODE_PRIVATE(node);
struct ng_mesg *resp = NULL;
struct ng_mesg *msg;
int error = 0;
u_int i;
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_GENERIC_COOKIE:
switch (msg->header.cmd) {
case NGM_TEXT_STATUS:
NG_MKRESPONSE(resp, msg, NG_TEXTRESPONSE, M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
resp->header.arglen = text_status(node, priv,
(char *)resp->data, resp->header.arglen) + 1;
break;
default:
error = EINVAL;
break;
}
break;
case NGM_UNI_COOKIE:
switch (msg->header.cmd) {
case NGM_UNI_SETDEBUG:
{
struct ngm_uni_debug *arg;
if (msg->header.arglen > sizeof(*arg)) {
error = EINVAL;
break;
}
arg = (struct ngm_uni_debug *)msg->data;
for (i = 0; i < UNI_MAXFACILITY; i++)
uni_set_debug(priv->uni, i, arg->level[i]);
break;
}
case NGM_UNI_GETDEBUG:
{
struct ngm_uni_debug *arg;
NG_MKRESPONSE(resp, msg, sizeof(*arg), M_NOWAIT);
if(resp == NULL) {
error = ENOMEM;
break;
}
arg = (struct ngm_uni_debug *)resp->data;
for (i = 0; i < UNI_MAXFACILITY; i++)
arg->level[i] = uni_get_debug(priv->uni, i);
break;
}
case NGM_UNI_GET_CONFIG:
{
struct uni_config *config;
if (msg->header.arglen != 0) {
error = EINVAL;
break;
}
NG_MKRESPONSE(resp, msg, sizeof(*config), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
config = (struct uni_config *)resp->data;
uni_get_config(priv->uni, config);
break;
}
case NGM_UNI_SET_CONFIG:
{
struct ngm_uni_set_config *arg;
struct ngm_uni_config_mask *mask;
if (msg->header.arglen != sizeof(*arg)) {
error = EINVAL;
break;
}
arg = (struct ngm_uni_set_config *)msg->data;
NG_MKRESPONSE(resp, msg, sizeof(*mask), M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
mask = (struct ngm_uni_config_mask *)resp->data;
*mask = arg->mask;
uni_set_config(priv->uni, &arg->config,
&mask->mask, &mask->popt_mask, &mask->option_mask);
break;
}
case NGM_UNI_ENABLE:
if (msg->header.arglen != 0) {
error = EINVAL;
break;
}
if (priv->enabled) {
error = EISCONN;
break;
}
priv->enabled = 1;
break;
case NGM_UNI_DISABLE:
if (msg->header.arglen != 0) {
error = EINVAL;
break;
}
if (!priv->enabled) {
error = ENOTCONN;
break;
}
priv->enabled = 0;
uni_reset(priv->uni);
break;
case NGM_UNI_GETSTATE:
if (msg->header.arglen != 0) {
error = EINVAL;
break;
}
NG_MKRESPONSE(resp, msg, sizeof(u_int32_t), M_NOWAIT);
if(resp == NULL) {
error = ENOMEM;
break;
}
*(u_int32_t *)resp->data =
priv->enabled ? (uni_getcustate(priv->uni) + 1)
: 0;
break;
default:
error = EINVAL;
break;
}
break;
default:
error = EINVAL;
break;
}
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/************************************************************/
/*
* HOOK MANAGEMENT
*/
static int
ng_uni_newhook(node_p node, hook_p hook, const char *name)
{
struct priv *priv = NG_NODE_PRIVATE(node);
if (strcmp(name, "lower") == 0) {
priv->lower = hook;
} else if(strcmp(name, "upper") == 0) {
priv->upper = hook;
NG_HOOK_SET_RCVDATA(hook, ng_uni_rcvupper);
} else
return EINVAL;
return 0;
}
static int
ng_uni_disconnect(hook_p hook)
{
node_p node = NG_HOOK_NODE(hook);
struct priv *priv = NG_NODE_PRIVATE(node);
if(hook == priv->lower)
priv->lower = NULL;
else if(hook == priv->upper)
priv->upper = NULL;
else
printf("%s: bogus hook %s\n", __func__, NG_HOOK_NAME(hook));
if (NG_NODE_NUMHOOKS(node) == 0) {
if (NG_NODE_IS_VALID(node))
ng_rmnode_self(node);
}
return (0);
}
/************************************************************/
/*
* DATA
*/
/*
* Receive signal from USER.
*
* Repackage the data into one large buffer.
*/
static int
ng_uni_rcvupper(hook_p hook, item_p item)
{
node_p node = NG_HOOK_NODE(hook);
struct priv *priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
struct uni_arg arg;
struct uni_msg *msg;
int error;
if (!priv->enabled) {
NG_FREE_ITEM(item);
return (ENOTCONN);
}
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
m_freem(m);
return (error);
}
m_freem(m);
if (uni_msg_len(msg) < sizeof(arg)) {
printf("%s: packet too short\n", __func__);
uni_msg_destroy(msg);
return (EINVAL);
}
bcopy(msg->b_rptr, &arg, sizeof(arg));
msg->b_rptr += sizeof(arg);
if (arg.sig >= UNIAPI_MAXSIG) {
printf("%s: bogus signal\n", __func__);
uni_msg_destroy(msg);
return (EINVAL);
}
uni_uni_input(priv->uni, arg.sig, arg.cookie, msg);
uni_work(priv->uni);
return (0);
}
/*
* Upper layer signal from UNI
*/
static void
uni_uni_output(struct uni *uni, void *varg, enum uni_sig sig, u_int32_t cookie,
struct uni_msg *msg)
{
node_p node = (node_p)varg;
struct priv *priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
struct uni_arg arg;
int error;
if (priv->upper == NULL) {
if (msg != NULL)
uni_msg_destroy(msg);
return;
}
arg.sig = sig;
arg.cookie = cookie;
m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
if (msg != NULL)
uni_msg_destroy(msg);
if (m == NULL)
return;
NG_SEND_DATA_ONLY(error, priv->upper, m);
}
static void
dump_uni_msg(struct uni_msg *msg)
{
u_int pos;
for (pos = 0; pos < uni_msg_len(msg); pos++) {
if (pos % 16 == 0)
printf("%06o ", pos);
if (pos % 16 == 8)
printf(" ");
printf(" %02x", msg->b_rptr[pos]);
if (pos % 16 == 15)
printf("\n");
}
if (pos % 16 != 0)
printf("\n");
}
/*
* Dump a SAAL signal in either direction
*/
static void
dump_saal_signal(node_p node, enum saal_sig sig, struct uni_msg *msg, int to)
{
struct priv *priv = NG_NODE_PRIVATE(node);
printf("signal %s SAAL: ", to ? "to" : "from");
switch (sig) {
#define D(S) case S: printf("%s", #S); break
D(SAAL_ESTABLISH_request);
D(SAAL_ESTABLISH_indication);
D(SAAL_ESTABLISH_confirm);
D(SAAL_RELEASE_request);
D(SAAL_RELEASE_confirm);
D(SAAL_RELEASE_indication);
D(SAAL_DATA_request);
D(SAAL_DATA_indication);
D(SAAL_UDATA_request);
D(SAAL_UDATA_indication);
#undef D
default:
printf("sig=%d", sig); break;
}
if (msg != NULL) {
printf(" data=%zu\n", uni_msg_len(msg));
if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 1)
dump_uni_msg(msg);
} else
printf("\n");
}
/*
* Receive signal from SSCOP.
*
* If this is a data signal, repackage the data into one large buffer.
* UNI shouldn't be the bottleneck in a system and this greatly simplifies
* parsing in UNI.
*/
static int
ng_uni_rcvlower(hook_p hook __unused, item_p item)
{
node_p node = NG_HOOK_NODE(hook);
struct priv *priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
struct sscfu_arg arg;
struct uni_msg *msg;
int error;
if (!priv->enabled) {
NG_FREE_ITEM(item);
return (ENOTCONN);
}
NGI_GET_M(item, m);
NG_FREE_ITEM(item);
if ((error = uni_msg_unpack_mbuf(m, &msg)) != 0) {
m_freem(m);
return (error);
}
m_freem(m);
if (uni_msg_len(msg) < sizeof(arg)) {
uni_msg_destroy(msg);
printf("%s: packet too short\n", __func__);
return (EINVAL);
}
bcopy(msg->b_rptr, &arg, sizeof(arg));
msg->b_rptr += sizeof(arg);
if (arg.sig > SAAL_UDATA_indication) {
uni_msg_destroy(msg);
printf("%s: bogus signal\n", __func__);
return (EINVAL);
}
if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
dump_saal_signal(node, arg.sig, msg, 0);
uni_saal_input(priv->uni, arg.sig, msg);
uni_work(priv->uni);
return (0);
}
/*
* Send signal to sscop.
* Pack the message into an mbuf chain.
*/
static void
uni_saal_output(struct uni *uni, void *varg, enum saal_sig sig, struct uni_msg *msg)
{
node_p node = (node_p)varg;
struct priv *priv = NG_NODE_PRIVATE(node);
struct mbuf *m;
struct sscfu_arg arg;
int error;
if (uni_get_debug(priv->uni, UNI_FAC_SAAL) > 0)
dump_saal_signal(node, sig, msg, 1);
if (priv->lower == NULL) {
if (msg != NULL)
uni_msg_destroy(msg);
return;
}
arg.sig = sig;
m = uni_msg_pack_mbuf(msg, &arg, sizeof(arg));
if (msg != NULL)
uni_msg_destroy(msg);
if (m == NULL)
return;
NG_SEND_DATA_ONLY(error, priv->lower, m);
}
static void
uni_verbose(struct uni *uni, void *varg, u_int fac, const char *fmt, ...)
{
va_list ap;
static char *facnames[] = {
#define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] #D,
UNI_DEBUG_FACILITIES
#undef UNI_DEBUG_DEFINE
};
printf("%s: ", facnames[fac]);
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
printf("\n");
}
/************************************************************/
/*
* Memory debugging
*/
struct unimem_debug {
const char *file;
u_int lno;
LIST_ENTRY(unimem_debug) link;
char data[0];
};
LIST_HEAD(unimem_debug_list, unimem_debug);
static struct unimem_debug_list nguni_freemem[UNIMEM_TYPES] = {
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
};
static struct unimem_debug_list nguni_usedmem[UNIMEM_TYPES] = {
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
LIST_HEAD_INITIALIZER(unimem_debug),
};
static struct mtx nguni_unilist_mtx;
static const char *unimem_names[UNIMEM_TYPES] = {
"instance",
"all",
"signal",
"call",
"party"
};
static void
uni_init(void)
{
mtx_init(&nguni_unilist_mtx, "netgraph UNI structure lists", NULL,
MTX_DEF);
}
static void
uni_fini(void)
{
u_int type;
struct unimem_debug *h;
for (type = 0; type < UNIMEM_TYPES; type++) {
while ((h = LIST_FIRST(&nguni_freemem[type])) != NULL) {
LIST_REMOVE(h, link);
free(h, M_UNI);
}
while ((h = LIST_FIRST(&nguni_usedmem[type])) != NULL) {
LIST_REMOVE(h, link);
printf("ng_uni: %s in use: %p (%s,%u)\n",
unimem_names[type], (caddr_t)h->data,
h->file, h->lno);
free(h, M_UNI);
}
}
mtx_destroy(&nguni_unilist_mtx);
}
/*
* Allocate a chunk of memory from a given type.
*/
void *
ng_uni_malloc(enum unimem type, const char *file, u_int lno)
{
struct unimem_debug *d;
size_t full;
/*
* Try to allocate
*/
mtx_lock(&nguni_unilist_mtx);
if ((d = LIST_FIRST(&nguni_freemem[type])) != NULL)
LIST_REMOVE(d, link);
mtx_unlock(&nguni_unilist_mtx);
if (d == NULL) {
/*
* allocate
*/
full = unimem_sizes[type] + offsetof(struct unimem_debug, data);
if ((d = malloc(full, M_UNI, M_NOWAIT | M_ZERO)) == NULL)
return (NULL);
} else {
bzero(d->data, unimem_sizes[type]);
}
d->file = file;
d->lno = lno;
mtx_lock(&nguni_unilist_mtx);
LIST_INSERT_HEAD(&nguni_usedmem[type], d, link);
mtx_unlock(&nguni_unilist_mtx);
return (d->data);
}
void
ng_uni_free(enum unimem type, void *ptr, const char *file, u_int lno)
{
struct unimem_debug *d, *h;
d = (struct unimem_debug *)
((char *)ptr - offsetof(struct unimem_debug, data));
mtx_lock(&nguni_unilist_mtx);
LIST_FOREACH(h, &nguni_usedmem[type], link)
if (d == h)
break;
if (h != NULL) {
LIST_REMOVE(d, link);
LIST_INSERT_HEAD(&nguni_freemem[type], d, link);
} else {
/*
* Not on used list - try free list.
*/
LIST_FOREACH(h, &nguni_freemem[type], link)
if (d == h)
break;
if (h == NULL)
printf("ng_uni: %s,%u: %p(%s) was never allocated\n",
file, lno, ptr, unimem_names[type]);
else
printf("ng_uni: %s,%u: %p(%s) was already destroyed "
"in %s,%u\n",
file, lno, ptr, unimem_names[type],
h->file, h->lno);
}
mtx_unlock(&nguni_unilist_mtx);
}
/************************************************************/
/*
* INITIALISATION
*/
/*
* Loading and unloading of node type
*/
static int
ng_uni_mod_event(module_t mod, int event, void *data)
{
int s;
int error = 0;
s = splnet();
switch(event) {
case MOD_LOAD:
uni_init();
break;
case MOD_UNLOAD:
uni_fini();
break;
default:
error = EOPNOTSUPP;
break;
}
splx(s);
return (error);
}