summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_base.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netgraph/ng_base.c')
-rw-r--r--sys/netgraph/ng_base.c79
1 files changed, 57 insertions, 22 deletions
diff --git a/sys/netgraph/ng_base.c b/sys/netgraph/ng_base.c
index c066580..c5c6a0e 100644
--- a/sys/netgraph/ng_base.c
+++ b/sys/netgraph/ng_base.c
@@ -79,7 +79,8 @@ static int ng_add_hook(node_p node, const char *name, hook_p * hookp);
static int ng_connect(hook_p hook1, hook_p hook2);
static void ng_disconnect_hook(hook_p hook);
static int ng_generic_msg(node_p here, struct ng_mesg *msg,
- const char *retaddr, struct ng_mesg ** resp);
+ const char *retaddr, struct ng_mesg ** resp,
+ hook_p hook);
static ng_ID_t ng_decodeidname(const char *name);
static int ngb_mod_event(module_t mod, int event, void *data);
static void ngintr(void);
@@ -1015,13 +1016,15 @@ ng_path_parse(char *addr, char **nodep, char **pathp, char **hookp)
* return the destination node. Compute the "return address" if desired.
*/
int
-ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp)
+ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp,
+ hook_p *lasthook)
{
const node_p start = here;
char fullpath[NG_PATHLEN + 1];
char *nodename, *path, pbuf[2];
node_p node;
char *cp;
+ hook_p hook = NULL;
/* Initialize */
if (rtnp)
@@ -1057,7 +1060,6 @@ ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp)
/* Now follow the sequence of hooks */
for (cp = path; node != NULL && *cp != '\0'; ) {
- hook_p hook;
char *segment;
/*
@@ -1112,6 +1114,8 @@ ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp)
/* Done */
*destp = node;
+ if (lasthook && hook)
+ *lasthook = hook->peer;
return (0);
}
@@ -1122,15 +1126,15 @@ ng_path2node(node_p here, const char *address, node_p *destp, char **rtnp)
* call the type's message handler (if it exists)
*/
-#define CALL_MSG_HANDLER(error, node, msg, retaddr, resp) \
+#define CALL_MSG_HANDLER(error, node, msg, retaddr, resp, hook) \
do { \
if((msg)->header.typecookie == NGM_GENERIC_COOKIE) { \
(error) = ng_generic_msg((node), (msg), \
- (retaddr), (resp)); \
+ (retaddr), (resp), (hook)); \
} else { \
if ((node)->type->rcvmsg != NULL) { \
(error) = (*(node)->type->rcvmsg)((node), \
- (msg), (retaddr), (resp)); \
+ (msg), (retaddr), (resp), (hook)); \
} else { \
TRAP_ERROR; \
FREE((msg), M_NETGRAPH); \
@@ -1150,9 +1154,10 @@ ng_send_msg(node_p here, struct ng_mesg *msg, const char *address,
node_p dest = NULL;
char *retaddr = NULL;
int error;
+ hook_p lasthook;
/* Find the target node */
- error = ng_path2node(here, address, &dest, &retaddr);
+ error = ng_path2node(here, address, &dest, &retaddr, &lasthook);
if (error) {
FREE(msg, M_NETGRAPH);
return error;
@@ -1162,7 +1167,7 @@ ng_send_msg(node_p here, struct ng_mesg *msg, const char *address,
if (rptr != NULL)
*rptr = NULL;
- CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr);
+ CALL_MSG_HANDLER(error, dest, msg, retaddr, rptr, lasthook);
/* Make sure that if there is a response, it has the RESP bit set */
if ((error == 0) && rptr && *rptr)
@@ -1182,7 +1187,7 @@ ng_send_msg(node_p here, struct ng_mesg *msg, const char *address,
*/
static int
ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
- struct ng_mesg **resp)
+ struct ng_mesg **resp, hook_p lasthook)
{
int error = 0;
@@ -1222,7 +1227,7 @@ ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
con->path[sizeof(con->path) - 1] = '\0';
con->ourhook[sizeof(con->ourhook) - 1] = '\0';
con->peerhook[sizeof(con->peerhook) - 1] = '\0';
- error = ng_path2node(here, con->path, &node2, NULL);
+ error = ng_path2node(here, con->path, &node2, NULL, NULL);
if (error)
break;
error = ng_con_nodes(here, con->ourhook, node2, con->peerhook);
@@ -1597,7 +1602,8 @@ ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
break;
}
if (here->type->rcvmsg != NULL)
- return((*here->type->rcvmsg)(here, msg, retaddr, resp));
+ return((*here->type->rcvmsg)(here, msg, retaddr,
+ resp, lasthook));
/* Fall through if rcvmsg not supported */
default:
TRAP_ERROR;
@@ -1612,16 +1618,18 @@ ng_generic_msg(node_p here, struct ng_mesg *msg, const char *retaddr,
* 'receive data' method, then silently discard the packet.
*/
int
-ng_send_data(hook_p hook, struct mbuf *m, meta_p meta)
+ng_send_data(hook_p hook, struct mbuf *m, meta_p meta,
+ struct mbuf **ret_m, meta_p *ret_meta)
{
- int (*rcvdata)(hook_p, struct mbuf *, meta_p);
+ ng_rcvdata_t *rcvdata;
int error;
CHECK_DATA_MBUF(m);
if (hook && (hook->flags & HK_INVALID) == 0) {
rcvdata = hook->peer->node->type->rcvdata;
if (rcvdata != NULL)
- error = (*rcvdata)(hook->peer, m, meta);
+ error = (*rcvdata)(hook->peer, m, meta,
+ ret_m, ret_meta);
else {
error = 0;
NG_FREE_DATA(m, meta);
@@ -1639,18 +1647,27 @@ ng_send_data(hook_p hook, struct mbuf *m, meta_p meta)
* 'receive queued data' method, then try the 'receive data' method above.
*/
int
-ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta)
+ng_send_dataq(hook_p hook, struct mbuf *m, meta_p meta,
+ struct mbuf **ret_m, meta_p *ret_meta)
{
- int (*rcvdataq)(hook_p, struct mbuf *, meta_p);
+ ng_rcvdata_t *rcvdata;
int error;
CHECK_DATA_MBUF(m);
if (hook && (hook->flags & HK_INVALID) == 0) {
- rcvdataq = hook->peer->node->type->rcvdataq;
- if (rcvdataq != NULL)
- error = (*rcvdataq)(hook->peer, m, meta);
+ rcvdata = hook->peer->node->type->rcvdataq;
+ if (rcvdata != NULL)
+ error = (*rcvdata)(hook->peer, m, meta,
+ ret_m, ret_meta);
else {
- error = ng_send_data(hook, m, meta);
+ rcvdata = hook->peer->node->type->rcvdata;
+ if (rcvdata != NULL) {
+ error = (*rcvdata)(hook->peer, m, meta,
+ ret_m, ret_meta);
+ } else {
+ error = 0;
+ NG_FREE_DATA(m, meta);
+ }
}
} else {
TRAP_ERROR;
@@ -1769,6 +1786,7 @@ struct ng_queue_entry {
struct ng_mesg *msg_msg;
node_p msg_node;
void *msg_retaddr;
+ hook_p msg_lasthook;
} msg;
} body;
};
@@ -1883,9 +1901,10 @@ ng_queue_msg(node_p here, struct ng_mesg *msg, const char *address)
node_p dest = NULL;
char *retaddr = NULL;
int error;
+ hook_p lasthook = NULL;
/* Find the target node. */
- error = ng_path2node(here, address, &dest, &retaddr);
+ error = ng_path2node(here, address, &dest, &retaddr, &lasthook);
if (error) {
FREE(msg, M_NETGRAPH);
return (error);
@@ -1903,7 +1922,10 @@ ng_queue_msg(node_p here, struct ng_mesg *msg, const char *address)
q->body.msg.msg_node = dest;
q->body.msg.msg_msg = msg;
q->body.msg.msg_retaddr = retaddr;
+ q->body.msg.msg_lasthook = lasthook;
dest->refs++; /* don't let it go away while on the queue */
+ if (lasthook)
+ lasthook->refs++; /* same for the hook */
/* Put it on the queue */
s = splhigh();
@@ -1960,12 +1982,25 @@ ngintr(void)
node = ngq->body.msg.msg_node;
msg = ngq->body.msg.msg_msg;
retaddr = ngq->body.msg.msg_retaddr;
+ hook = ngq->body.msg.msg_lasthook;
RETURN_QBLK(ngq);
+ if (hook) {
+ if ((hook->refs == 1)
+ || (hook->flags & HK_INVALID) != 0) {
+ /* If the hook only has one ref left
+ then we can't use it */
+ ng_unref_hook(hook);
+ hook = NULL;
+ } else {
+ ng_unref_hook(hook);
+ }
+ }
+ /* similarly, if the node is a zombie.. */
if (node->flags & NG_INVALID) {
FREE(msg, M_NETGRAPH);
} else {
CALL_MSG_HANDLER(error, node, msg,
- retaddr, NULL);
+ retaddr, NULL, hook);
}
ng_unref(node);
if (retaddr)
OpenPOWER on IntegriCloud