#include <sys/taskqueue.h>
#include <machine/cpu.h>
-#include <net/netisr.h>
-
#include <netgraph7/ng_message.h>
#include <netgraph7/netgraph.h>
#include <netgraph7/ng_parse.h>
void ng_rmnode(node_p node, hook_p dummy1, void *dummy2, int dummy3);
void ng_unname(node_p node);
-
/* Our own netgraph malloc type */
MALLOC_DEFINE(M_NETGRAPH, "netgraph", "netgraph structures and ctrl messages");
MALLOC_DEFINE(M_NETGRAPH_HOOK, "netgraph_hook", "netgraph hook structures");
#define NG_WORKLIST_UNLOCK() \
mtx_unlock(&ng_worklist_mtx)
-#define NG_FREE_HOOK(hook) do { kfree((hook), M_NETGRAPH_HOOK); } while (0)
-#define NG_FREE_NODE(node) do { kfree((node), M_NETGRAPH_NODE); } while (0)
-
-/* Set this to kdb_enter("X") to catch all errors as they occur */
-#ifndef TRAP_ERROR
-#define TRAP_ERROR()
-#endif
-
static ng_ID_t nextID = 1;
#ifdef INVARIANTS
int error;
/* Check that the type makes sense */
- if (typename == NULL) {
- TRAP_ERROR();
+ if (typename == NULL)
return (EINVAL);
- }
/* Locate the node type. If we fail we return. Do not try to load
* module.
if ((type = ng_findtype(typename)) == NULL)
return (ENXIO);
- /*
- * If we have a constructor, then make the node and
- * call the constructor to do type specific initialisation.
- */
- if (type->constructor != NULL) {
- if ((error = ng_make_node_common(type, nodepp)) == 0) {
- if ((error = ((*type->constructor)(*nodepp)) != 0)) {
- NG_NODE_UNREF(*nodepp);
- }
- }
- } else {
+ if (type->constructor == NULL) {
/*
* Node has no constructor. We cannot ask for one
* to be made. It must be brought into existence by
* call ng_make_node_common() directly to get the
* netgraph part initialised.
*/
- TRAP_ERROR();
- error = EINVAL;
+ return (EINVAL);
}
+
+ /*
+ * If we have a constructor, then make the node and
+ * call the constructor to do type specific initialisation.
+ */
+ if ((error = ng_make_node_common(type, nodepp)) == 0) {
+ if ((error = ((*type->constructor)(*nodepp)) != 0)) {
+ NG_NODE_UNREF(*nodepp);
+ }
+ }
+
return (error);
}
/* Require the node type to have been already installed */
if (ng_findtype(type->name) == NULL) {
- TRAP_ERROR();
return (EINVAL);
}
mtx_unlock(&ng_idhash_mtx);
mtx_uninit(&node->nd_input_queue.q_mtx);
- NG_FREE_NODE(node);
+ kfree(node, M_NETGRAPH_NODE);
}
return (v - 1);
}
break;
}
if (i == 0 || name[i] != '\0') {
- TRAP_ERROR();
return (EINVAL);
}
if (ng_decodeidname(name) != 0) { /* valid IDs not allowed here */
- TRAP_ERROR();
return (EINVAL);
}
/* Check the name isn't already being used */
if ((node2 = ng_name2noderef(node, name)) != NULL) {
NG_NODE_UNREF(node2);
- TRAP_ERROR();
return (EADDRINUSE);
}
if (v == 1) { /* we were the last */
if (_NG_HOOK_NODE(hook)) /* it'll probably be ng_deadnode */
_NG_NODE_UNREF((_NG_HOOK_NODE(hook)));
- NG_FREE_HOOK(hook);
+ kfree(hook, M_NETGRAPH_HOOK);
}
}
/* Check that the given name is good */
if (name == NULL) {
- TRAP_ERROR();
return (EINVAL);
}
if (ng_findhook(node, name) != NULL) {
- TRAP_ERROR();
return (EEXIST);
}
ng_bypass(hook_p hook1, hook_p hook2)
{
if (hook1->hk_node != hook2->hk_node) {
- TRAP_ERROR();
return (EINVAL);
}
hook1->hk_peer->hk_peer = hook2->hk_peer;
if ((tp->version != NG_ABI_VERSION)
|| (namelen == 0)
|| (namelen >= NG_TYPESIZ)) {
- TRAP_ERROR();
if (tp->version != NG_ABI_VERSION) {
printf("Netgraph: Node type rejected. ABI mismatch. Suggest recompile\n");
}
/* Check for name collision */
if (ng_findtype(tp->name) != NULL) {
- TRAP_ERROR();
return (EEXIST);
}
{
/* Check for name collision */
if (tp->refs != 1) {
- TRAP_ERROR();
return (EBUSY);
}
* Should not happen because we checked before queueing this.
*/
if (ng_findhook(node, NG_HOOK_NAME(hook)) != NULL) {
- TRAP_ERROR();
ng_destroy_hook(hook); /* should destroy peer too */
printf("failed in ng_con_part2()\n");
ERROUT(EEXIST);
/* Initialize */
if (destp == NULL) {
- TRAP_ERROR();
return EINVAL;
}
*destp = NULL;
/* Parse out node and sequence of hooks */
if (ng_path_parse(fullpath, &nodename, &path, NULL) < 0) {
- TRAP_ERROR();
return EINVAL;
}
if (path == NULL) {
if (nodename) {
node = ng_name2noderef(here, nodename);
if (node == NULL) {
- TRAP_ERROR();
return (ENOENT);
}
} else {
if (here == NULL) {
- TRAP_ERROR();
return (EINVAL);
}
node = here;
|| NG_HOOK_PEER(hook) == NULL
|| NG_HOOK_NOT_VALID(hook)
|| NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook))) {
- TRAP_ERROR();
NG_NODE_UNREF(node);
-#if 0
- printf("hooknotvalid %s %s %d %d %d %d ",
- path,
- segment,
- hook == NULL,
- NG_HOOK_PEER(hook) == NULL,
- NG_HOOK_NOT_VALID(hook),
- NG_HOOK_NOT_VALID(NG_HOOK_PEER(hook)));
-#endif
return (ENOENT);
}
/* If node somehow missing, fail here (probably this is not needed) */
if (node == NULL) {
- TRAP_ERROR();
return (ENXIO);
}
/* If there is nothing queued, then just return. */
if (!QUEUE_ACTIVE(ngq)) {
- CTR4(KTR_NET, "%20s: node [%x] (%p) queue empty; "
- "queue flags 0x%lx", __func__,
- node->nd_ID, node, ngq->q_flags);
return (NULL);
}
long t = ngq->q_flags;
if (t & WRITER_ACTIVE) {
/* There is writer, reader can't proceed. */
- CTR4(KTR_NET, "%20s: node [%x] (%p) queued reader "
- "can't proceed; queue flags 0x%lx", __func__,
- node->nd_ID, node, t);
return (NULL);
}
if (atomic_cmpset_acq_int(&ngq->q_flags, t,
*rw = NGQRW_W;
} else {
/* There is somebody other, writer can't proceed. */
- CTR4(KTR_NET, "%20s: node [%x] (%p) queued writer "
- "can't proceed; queue flags 0x%lx", __func__,
- node->nd_ID, node, ngq->q_flags);
return (NULL);
}
STAILQ_REMOVE_HEAD(&ngq->queue, el_next);
if (STAILQ_EMPTY(&ngq->queue))
atomic_clear_int(&ngq->q_flags, OP_PENDING);
- CTR6(KTR_NET, "%20s: node [%x] (%p) returning item %p as %s; "
- "queue flags 0x%lx", __func__,
- node->nd_ID, node, item, *rw ? "WRITER" : "READER" ,
- ngq->q_flags);
return (item);
}
atomic_set_int(&ngq->q_flags, OP_PENDING);
STAILQ_INSERT_TAIL(&ngq->queue, item, el_next);
- CTR5(KTR_NET, "%20s: node [%x] (%p) queued item %p as %s", __func__,
- node->nd_ID, node, item, rw ? "WRITER" : "READER" );
-
/*
* We can take the worklist lock with the node locked
* BUT NOT THE REVERSE!
if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags,
t, t + READER_INCREMENT)) {
/* Successfully grabbed node */
- CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p",
- __func__, node->nd_ID, node, item);
return (item);
}
cpu_spinwait();
if (atomic_cmpset_acq_int(&node->nd_input_queue.q_flags,
0, WRITER_ACTIVE)) {
/* Successfully grabbed node */
- CTR4(KTR_NET, "%20s: node [%x] (%p) acquired item %p",
- __func__, node->nd_ID, node, item);
return (item);
}
return (NULL);
}
-#if 0
-static __inline item_p
-ng_upgrade_write(node_p node, item_p item)
-{
- struct ng_queue *ngq = &node->nd_input_queue;
- KASSERT(node != &ng_deadnode,
- ("%s: working on deadnode", __func__));
-
- NGI_SET_WRITER(item);
-
- NG_QUEUE_LOCK(ngq);
-
- /*
- * There will never be no readers as we are there ourselves.
- * Set the WRITER_ACTIVE flags ASAP to block out fast track readers.
- * The caller we are running from will call ng_leave_read()
- * soon, so we must account for that. We must leave again with the
- * READER lock. If we find other readers, then
- * queue the request for later. However "later" may be rignt now
- * if there are no readers. We don't really care if there are queued
- * items as we will bypass them anyhow.
- */
- atomic_add_int(&ngq->q_flags, WRITER_ACTIVE - READER_INCREMENT);
- if ((ngq->q_flags & (NGQ_WMASK & ~OP_PENDING)) == WRITER_ACTIVE) {
- NG_QUEUE_UNLOCK(ngq);
-
- /* It's just us, act on the item. */
- /* will NOT drop writer lock when done */
- ng_apply_item(node, item, 0);
-
- /*
- * Having acted on the item, atomically
- * down grade back to READER and finish up
- */
- atomic_add_int(&ngq->q_flags,
- READER_INCREMENT - WRITER_ACTIVE);
-
- /* Our caller will call ng_leave_read() */
- return;
- }
- /*
- * It's not just us active, so queue us AT THE HEAD.
- * "Why?" I hear you ask.
- * Put us at the head of the queue as we've already been
- * through it once. If there is nothing else waiting,
- * set the correct flags.
- */
- if (STAILQ_EMPTY(&ngq->queue)) {
- /* We've gone from, 0 to 1 item in the queue */
- atomic_set_int(&ngq->q_flags, OP_PENDING);
-
- CTR3(KTR_NET, "%20s: node [%x] (%p) set OP_PENDING", __func__,
- node->nd_ID, node);
- };
- STAILQ_INSERT_HEAD(&ngq->queue, item, el_next);
- CTR4(KTR_NET, "%20s: node [%x] (%p) requeued item %p as WRITER",
- __func__, node->nd_ID, node, item );
-
- /* Reverse what we did above. That downgrades us back to reader */
- atomic_add_int(&ngq->q_flags, READER_INCREMENT - WRITER_ACTIVE);
- if (QUEUE_ACTIVE(ngq) && NEXT_QUEUED_ITEM_CAN_PROCEED(ngq))
- ng_worklist_add(node);
- NG_QUEUE_UNLOCK(ngq);
-
- return;
-}
-#endif
-
/* Release reader lock. */
static __inline void
ng_leave_read(node_p node)
* nothing we can do with it, drop everything.
*/
if (NG_NODE_NOT_VALID(node)) {
- TRAP_ERROR();
error = EINVAL;
NG_FREE_ITEM(item);
break;
}
if (((!hook) || (!(rcvmsg = hook->hk_rcvmsg))) &&
(!(rcvmsg = node->nd_type->rcvmsg))) {
- TRAP_ERROR();
error = 0;
NG_FREE_ITEM(item);
break;
*/
if ((NG_NODE_NOT_VALID(node))
&& (NGI_FN(item) != &ng_rmnode)) {
- TRAP_ERROR();
error = EINVAL;
NG_FREE_ITEM(item);
break;
NGI_GET_MSG(item, msg);
if (msg->header.typecookie != NGM_GENERIC_COOKIE) {
- TRAP_ERROR();
error = EINVAL;
goto out;
}
struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data;
if (msg->header.arglen != sizeof(*mkp)) {
- TRAP_ERROR();
error = EINVAL;
break;
}
node_p node2;
if (msg->header.arglen != sizeof(*con)) {
- TRAP_ERROR();
error = EINVAL;
break;
}
struct ngm_name *const nam = (struct ngm_name *) msg->data;
if (msg->header.arglen != sizeof(*nam)) {
- TRAP_ERROR();
error = EINVAL;
break;
}
hook_p hook;
if (msg->header.arglen != sizeof(*rmh)) {
- TRAP_ERROR();
error = EINVAL;
break;
}
if (msg->header.arglen < sizeof(struct ng_mesg) ||
(msg->header.arglen - sizeof(struct ng_mesg) <
binary->header.arglen)) {
- TRAP_ERROR();
error = EINVAL;
break;
}
(ascii->header.arglen < 1) ||
(msg->header.arglen < sizeof(*ascii) +
ascii->header.arglen)) {
- TRAP_ERROR();
error = EINVAL;
break;
}
}
/* Fall through if rcvmsg not supported */
default:
- TRAP_ERROR();
error = EINVAL;
}
/*
}
STAILQ_REMOVE_HEAD(&ng_worklist, nd_input_queue.q_work);
NG_WORKLIST_UNLOCK();
- CTR3(KTR_NET, "%20s: node [%x] (%p) taken off worklist",
- __func__, node->nd_ID, node);
/*
* We have the node. We also take over the reference
* that the list had on it.
KKASSERT(mtx_owned(&node->nd_input_queue.q_mtx));
+ /* If not already on worklist */
if ((node->nd_input_queue.q_flags2 & NGQ2_WORKQ) == 0) {
static struct task ng_task;
NG_WORKLIST_UNLOCK();
TASK_INIT(&ng_task, 0, ngtask, NULL);
taskqueue_enqueue(taskqueue_swi, &ng_task);
- CTR3(KTR_NET, "%20s: node [%x] (%p) put on worklist", __func__,
- node->nd_ID, node);
- } else {
- CTR3(KTR_NET, "%20s: node [%x] (%p) already on worklist",
- __func__, node->nd_ID, node);
}
}
NG_HOOK_NOT_VALID(peer = NG_HOOK_PEER(hook)) ||
NG_NODE_NOT_VALID(peernode = NG_PEER_NODE(hook))) {
NG_FREE_ITEM(item);
- TRAP_ERROR();
return (ENETDOWN);
}
dest = ng_ID2noderef(ID); /* GETS REFERENCE! */
if (dest == NULL) {
NG_FREE_ITEM(item);
- TRAP_ERROR();
return(EINVAL);
}
/* Fill out the contents */
*/
ptn = (((const char *)(pt + 1)) + ntohs(pt->tag_len));
if (ptn > end) {
- CTR2(KTR_NET, "%20s: invalid length for tag %d",
- __func__, idx);
return (NULL);
}
if (pt->tag_type == idx) {
- CTR2(KTR_NET, "%20s: found tag %d", __func__, idx);
return (pt);
}
pt = (const struct pppoe_tag*)ptn;
}
- CTR2(KTR_NET, "%20s: not found tag %d", __func__, idx);
return (NULL);
}
KASSERT((sp->neg != NULL) && (sp->neg->m != NULL),
("%s: called from wrong state", __func__));
- CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
dp = (char *)wh->ph.tag;
for (count = 0, tag = sp->neg->tags;
ntohs(tag->tag_len)) == 0)
break;
}
- CTR3(KTR_NET, "%20s: matched %p for %s", __func__,
- sp?sp->hook:NULL, tag->tag_data);
return (sp?sp->hook:NULL);
}
if (tsp)
goto restart;
- CTR2(KTR_NET, "%20s: new sid %d", __func__, val);
-
return (val);
}
}
}
mtx_unlock(&privp->sesshash[hash].mtx);
- CTR3(KTR_NET, "%20s: matched %p for %d", __func__, sp?sp->hook:NULL,
- session);
return (sp);
}
if (uniq.pointer == NG_HOOK_PRIVATE(hook))
break;
}
- CTR3(KTR_NET, "%20s: matched %p for %p", __func__, hook, uniq.pointer);
return (hook);
}
LIST_INIT(&privp->sesshash[i].head);
}
- CTR3(KTR_NET, "%20s: created node [%x] (%p)",
- __func__, node->nd_ID, node);
-
return (0);
}
NG_HOOK_SET_PRIVATE(hook, sp);
sp->hook = hook;
}
- CTR5(KTR_NET, "%20s: node [%x] (%p) connected hook %s (%p)",
- __func__, node->nd_ID, node, name, hook);
return(0);
}
struct ng_mesg *msg;
NGI_GET_MSG(item, msg);
- CTR5(KTR_NET, "%20s: node [%x] (%p) got message %d with cookie %d",
- __func__, node->nd_ID, node, msg->header.cmd,
- msg->header.typecookie);
/* Deal with message according to cookie and command. */
switch (msg->header.typecookie) {
/* Take care of synchronous response, if any. */
quit:
- CTR2(KTR_NET, "%20s: returning %d", __func__, error);
NG_RESPOND_MSG(error, node, item, resp);
/* Free the message and return. */
NG_FREE_MSG(msg);
/*
* Kick the state machine into starting up.
*/
- CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
sp->state = PPPOE_SINIT;
/*
* Reset the packet header to broadcast. Since we are
struct ng_mesg *msg;
struct ngpppoe_sts *sts;
- CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
-
NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, NGM_PPPOE_ACNAME,
sizeof(struct ngpppoe_sts), M_WAITOK | M_NULLOK);
if (msg == NULL)
int error;
struct ng_mesg *msg;
- CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
-
NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, NGM_PPPOE_SESSIONID,
sizeof(uint16_t), M_WAITOK | M_NULLOK);
if (msg == NULL)
struct mbuf *m;
int error;
- CTR6(KTR_NET, "%20s: node [%x] (%p) received %p on \"%s\" (%p)",
- __func__, node->nd_ID, node, item, hook->hk_name, hook);
-
NGI_GET_M(item, m);
switch (sp->state) {
case PPPOE_NEWCONNECTED:
uint8_t code;
struct mbuf *m0;
- CTR6(KTR_NET, "%20s: node [%x] (%p) received %p on \"%s\" (%p)",
- __func__, node->nd_ID, node, item, hook->hk_name, hook);
-
NGI_GET_M(item, m);
/*
* Dig out various fields from the packet.
*/
tag = get_tag(ph, PTT_SRV_NAME);
if (tag == NULL) {
- CTR1(KTR_NET, "%20s: PADI w/o Service-Name",
- __func__);
LEAVE(ENETUNREACH);
}
const priv_p privp = NG_NODE_PRIVATE(node);
int error;
- CTR6(KTR_NET, "%20s: node [%x] (%p) received %p on \"%s\" (%p)",
- __func__, node->nd_ID, node, item, hook->hk_name, hook);
-
NG_FWD_ITEM_HOOK(error, item, privp->ethernet_hook);
privp->packets_out++;
return (error);
struct mbuf *m0 = NULL;
int error = 0;
- CTR6(KTR_NET, "%20s: node [%x] (%p) hook \"%s\" (%p) session %d",
- __func__, node->nd_ID, node, hook->hk_name, hook, sp->Session_ID);
switch(sp->state) {
/*
* Resend the last packet, using an exponential backoff.
/*
* Keep processing tags while a tag header will still fit.
*/
- CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
-
while((const char*)(pt + 1) <= end) {
/*
* If the tag data would go past the end of the packet, abort.
struct ng_mesg *msg;
struct ngpppoe_sts *sts;
- CTR2(KTR_NET, "%20s: called %d", __func__, sp->Session_ID);
-
NG_MKMESSAGE(msg, NGM_PPPOE_COOKIE, cmdid,
sizeof(struct ngpppoe_sts), M_WAITOK | M_NULLOK);
if (msg == NULL)