static void sscfu_send_lower(struct sscfu *sscf, void *p, enum sscop_aasig sig, struct mbuf *m, u_int arg) { node_p node = (node_p)p; struct priv *priv = NG_NODE_PRIVATE(node); int error; struct sscop_arg *a; if (priv->lower == NULL) { if (m != NULL) m_freem(m); return; } if (m == NULL) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return; m->m_len = sizeof(struct sscop_arg); m->m_pkthdr.len = m->m_len; } else { M_PREPEND(m, sizeof(struct sscop_arg), M_NOWAIT); if (m == NULL) return; } a = mtod(m, struct sscop_arg *); a->sig = sig; a->arg = arg; NG_SEND_DATA_ONLY(error, priv->lower, m); }
/* * Add a new hook */ static int ng_vjc_newhook(node_p node, hook_p hook, const char *name) { const priv_p priv = NG_NODE_PRIVATE(node); hook_p *hookp; /* Get hook */ if (strcmp(name, NG_VJC_HOOK_IP) == 0) hookp = &priv->ip; else if (strcmp(name, NG_VJC_HOOK_VJCOMP) == 0) hookp = &priv->vjcomp; else if (strcmp(name, NG_VJC_HOOK_VJUNCOMP) == 0) hookp = &priv->vjuncomp; else if (strcmp(name, NG_VJC_HOOK_VJIP) == 0) hookp = &priv->vjip; else return (EINVAL); /* See if already connected */ if (*hookp) return (EISCONN); /* OK */ *hookp = hook; return (0); }
static int ng_sscfu_rcvlower(hook_p hook, item_p item) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); struct mbuf *m; struct sscop_arg a; if (!priv->enabled || priv->upper == NULL) { NG_FREE_ITEM(item); return (0); } NGI_GET_M(item, m); NG_FREE_ITEM(item); if (!(m->m_flags & M_PKTHDR)) { printf("no pkthdr\n"); m_freem(m); return (EINVAL); } /* * Strip of the SSCOP header. */ if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) return (ENOMEM); bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); m_adj(m, sizeof(a)); sscfu_input(priv->sscf, a.sig, m, a.arg); return (0); }
static void bt3c_forward(node_p node, hook_p hook, void *arg1, int arg2) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); struct mbuf *m = NULL; int error; if (sc == NULL) return; if (sc->hook != NULL && NG_HOOK_IS_VALID(sc->hook)) { for (;;) { IF_DEQUEUE(&sc->inq, m); if (m == NULL) break; NG_SEND_DATA_ONLY(error, sc->hook, m); if (error != 0) NG_BT3C_STAT_IERROR(sc->stat); } } else { IF_LOCK(&sc->inq); for (;;) { _IF_DEQUEUE(&sc->inq, m); if (m == NULL) break; NG_BT3C_STAT_IERROR(sc->stat); NG_FREE_M(m); } IF_UNLOCK(&sc->inq); } } /* bt3c_forward */
/* * Destroy node */ static int ng_ksocket_shutdown(node_p node) { const priv_p priv = NG_NODE_PRIVATE(node); priv_p embryo; /* Close our socket (if any) */ if (priv->so != NULL) { atomic_clear_int(&priv->so->so_rcv.ssb_flags, SSB_UPCALL); atomic_clear_int(&priv->so->so_snd.ssb_flags, SSB_UPCALL); priv->so->so_upcall = NULL; soclose(priv->so, FNONBLOCK); priv->so = NULL; } /* If we are an embryo, take ourselves out of the parent's list */ if (priv->flags & KSF_EMBRYONIC) { LIST_REMOVE(priv, siblings); priv->flags &= ~KSF_EMBRYONIC; } /* Remove any embryonic children we have */ while (!LIST_EMPTY(&priv->embryos)) { embryo = LIST_FIRST(&priv->embryos); ng_rmnode_self(embryo->node); } /* Take down netgraph node */ bzero(priv, sizeof(*priv)); kfree(priv, M_NETGRAPH); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); /* let the node escape */ return (0); }
static int ng_sscop_rcvupper(hook_p hook, item_p item) { struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct sscop_arg a; struct mbuf *m; if (!priv->enabled) { NG_FREE_ITEM(item); return (EINVAL); } /* * If the lower layer is not connected allow to proceed. * The lower layer sending function will drop outgoing frames, * and the sscop will timeout any establish requests. */ NGI_GET_M(item, m); NG_FREE_ITEM(item); if (!(m->m_flags & M_PKTHDR)) { printf("no pkthdr\n"); m_freem(m); return (EINVAL); } if (m->m_len < (int)sizeof(a) && (m = m_pullup(m, sizeof(a))) == NULL) return (ENOBUFS); bcopy((caddr_t)mtod(m, struct sscop_arg *), &a, sizeof(a)); m_adj(m, sizeof(a)); return (sscop_aasig(priv->sscop, a.sig, m, a.arg)); }
static void sscop_send_manage(struct sscop *sscop, void *p, enum sscop_maasig sig, struct SSCOP_MBUF_T *m, u_int err, u_int cnt) { node_p node = (node_p)p; struct priv *priv = NG_NODE_PRIVATE(node); int error; struct sscop_merr *e; struct sscop_marg *a; if (priv->manage == NULL) { if (m != NULL) m_freem(m); priv->stats.maa_dropped++; return; } if (sig == SSCOP_MERROR_indication) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return; m->m_len = sizeof(*e); m->m_pkthdr.len = m->m_len; e = mtod(m, struct sscop_merr *); e->sig = sig; e->err = err; e->cnt = cnt; priv->stats.errors++; } else if (m == NULL) {
/* * DATA */ static int ng_sscop_rcvlower(hook_p hook, item_p item) { struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct mbuf *m; if (!priv->enabled) { NG_FREE_ITEM(item); return EINVAL; } /* * If we are disconnected at the upper layer and in the IDLE * state, drop any incoming packet. */ if (priv->upper != NULL || sscop_getstate(priv->sscop) != SSCOP_IDLE) { NGI_GET_M(item, m); priv->stats.in_packets++; sscop_input(priv->sscop, m); } else { priv->stats.in_dropped++; } NG_FREE_ITEM(item); return (0); }
/* * Give our ok for a hook to be added... * If we are not running this might kick a device into life. * Possibly decode information out of the hook name. * Add the hook's private info to the hook structure. * (if we had some). In this example, we assume that there is a * an array of structs, called 'channel' in the private info, * one for each active channel. The private * pointer of each hook points to the appropriate XXX_hookinfo struct * so that the source of an input packet is easily identified. * (a dlci is a frame relay channel) */ static int ng_xxx_newhook(node_p node, hook_p hook, const char *name) { const xxx_p xxxp = NG_NODE_PRIVATE(node); const char *cp; int dlci = 0; int chan; #if 0 /* Possibly start up the device if it's not already going */ if ((xxxp->flags & SCF_RUNNING) == 0) { ng_xxx_start_hardware(xxxp); } #endif /* Example of how one might use hooks with embedded numbers: All * hooks start with 'dlci' and have a decimal trailing channel * number up to 4 digits Use the leadin defined int he associated .h * file. */ if (strncmp(name, NG_XXX_HOOK_DLCI_LEADIN, strlen(NG_XXX_HOOK_DLCI_LEADIN)) == 0) { char *eptr; cp = name + strlen(NG_XXX_HOOK_DLCI_LEADIN); if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) return (EINVAL); dlci = (int)strtoul(cp, &eptr, 10); if (*eptr != '\0' || dlci < 0 || dlci > 1023) return (EINVAL); /* We have a dlci, now either find it, or allocate it */ for (chan = 0; chan < XXX_NUM_DLCIS; chan++) if (xxxp->channel[chan].dlci == dlci) break; if (chan == XXX_NUM_DLCIS) { for (chan = 0; chan < XXX_NUM_DLCIS; chan++) if (xxxp->channel[chan].dlci == -2) break; if (chan == XXX_NUM_DLCIS) return (ENOBUFS); xxxp->channel[chan].dlci = dlci; } if (xxxp->channel[chan].hook != NULL) return (EADDRINUSE); NG_HOOK_SET_PRIVATE(hook, xxxp->channel + chan); xxxp->channel[chan].hook = hook; return (0); } else if (strcmp(name, NG_XXX_HOOK_DOWNSTREAM) == 0) { /* Example of simple predefined hooks. */ /* do something specific to the downstream connection */ xxxp->downstream_hook.hook = hook; NG_HOOK_SET_PRIVATE(hook, &xxxp->downstream_hook); } else if (strcmp(name, NG_XXX_HOOK_DEBUG) == 0) { /* do something specific to a debug connection */ xxxp->debughook = hook; NG_HOOK_SET_PRIVATE(hook, NULL); } else return (EINVAL); /* not a hook we know about */ return(0); }
/* * Add a hook */ static int ngt_newhook(node_p node, hook_p hook, const char *name) { const sc_p sc = NG_NODE_PRIVATE(node); if (strcmp(name, NG_TEE_HOOK_RIGHT) == 0) { sc->right.hook = hook; bzero(&sc->right.stats, sizeof(sc->right.stats)); NG_HOOK_SET_PRIVATE(hook, &sc->right); } else if (strcmp(name, NG_TEE_HOOK_LEFT) == 0) { sc->left.hook = hook; bzero(&sc->left.stats, sizeof(sc->left.stats)); NG_HOOK_SET_PRIVATE(hook, &sc->left); } else if (strcmp(name, NG_TEE_HOOK_RIGHT2LEFT) == 0) { sc->right2left.hook = hook; bzero(&sc->right2left.stats, sizeof(sc->right2left.stats)); NG_HOOK_SET_PRIVATE(hook, &sc->right2left); } else if (strcmp(name, NG_TEE_HOOK_LEFT2RIGHT) == 0) { sc->left2right.hook = hook; bzero(&sc->left2right.stats, sizeof(sc->left2right.stats)); NG_HOOK_SET_PRIVATE(hook, &sc->left2right); } else return (EINVAL); return (0); }
/* * Receive incoming data on our hook. Send it out the socket. */ static int ng_ksocket_rcvdata(hook_p hook, item_p item) { struct thread *td = curthread; /* XXX broken */ const node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); struct socket *const so = priv->so; struct sockaddr *sa = NULL; int error; struct mbuf *m; struct sa_tag *stag; /* Extract data */ NGI_GET_M(item, m); NG_FREE_ITEM(item); /* * Look if socket address is stored in packet tags. * If sockaddr is ours, or provided by a third party (zero id), * then we accept it. */ if (((stag = (struct sa_tag *)m_tag_locate(m, NGM_KSOCKET_COOKIE, NG_KSOCKET_TAG_SOCKADDR, NULL)) != NULL) && (stag->id == NG_NODE_ID(node) || stag->id == 0)) sa = &stag->sa; /* Reset specific mbuf flags to prevent addressing problems. */ m->m_flags &= ~(M_BCAST|M_MCAST); /* Send packet */ error = sosend(so, sa, 0, m, 0, 0, td); return (error); }
static int ng_bt3c_shutdown(node_p node) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); /* Let old node go */ NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); /* Create new fresh one if we are not going down */ if (sc == NULL) goto out; /* Create new Netgraph node */ if (ng_make_node_common(&typestruct, &sc->node) != 0) { device_printf(sc->dev, "Could not create Netgraph node\n"); sc->node = NULL; goto out; } /* Name new Netgraph node */ if (ng_name_node(sc->node, device_get_nameunit(sc->dev)) != 0) { device_printf(sc->dev, "Could not name Netgraph node\n"); NG_NODE_UNREF(sc->node); sc->node = NULL; goto out; } NG_NODE_SET_PRIVATE(sc->node, sc); out: return (0); } /* ng_bt3c_shutdown */
static int ng_sscop_disconnect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); if(hook == priv->upper) priv->upper = NULL; else if(hook == priv->lower) priv->lower = NULL; else if(hook == priv->manage) priv->manage = NULL; if(NG_NODE_NUMHOOKS(node) == 0) { if(NG_NODE_IS_VALID(node)) ng_rmnode_self(node); } else { /* * Imply a release request, if the upper layer is * disconnected. */ if(priv->upper == NULL && priv->lower != NULL && priv->enabled && sscop_getstate(priv->sscop) != SSCOP_IDLE) { sscop_aasig(priv->sscop, SSCOP_RELEASE_request, NULL, 0); } } return 0; }
static int ng_sscfu_disconnect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct priv *priv = NG_NODE_PRIVATE(node); if (hook == priv->upper) priv->upper = NULL; else if (hook == priv->lower) priv->lower = NULL; else { log(LOG_ERR, "bogus hook"); return (EINVAL); } if (NG_NODE_NUMHOOKS(node) == 0) { if (NG_NODE_IS_VALID(node)) ng_rmnode_self(node); } else { /* * Because there are no timeouts reset the protocol * if the lower layer is disconnected. */ if (priv->lower == NULL && priv->enabled && sscfu_getstate(priv->sscf) != SSCFU_RELEASED) sscfu_reset(priv->sscf); } return (0); }
static int ng_ubt_disconnect(hook_p hook) { struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); UBT_NG_LOCK(sc); if (hook != sc->sc_hook) { UBT_NG_UNLOCK(sc); return (EINVAL); } sc->sc_hook = NULL; /* Kick off task to stop all USB xfers */ ubt_task_schedule(sc, UBT_FLAG_T_STOP_ALL); /* Drain queues */ NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq); NG_BT_MBUFQ_DRAIN(&sc->sc_aclq); NG_BT_MBUFQ_DRAIN(&sc->sc_scoq); UBT_NG_UNLOCK(sc); return (0); } /* ng_ubt_disconnect */
/* * Do local shutdown processing.. * All our links and the name have already been removed. * If we are a persistant device, we might refuse to go away. * In the case of a persistant node we signal the framework that we * are still in business by clearing the NGF_INVALID bit. However * If we find the NGF_REALLY_DIE bit set, this means that * we REALLY need to die (e.g. hardware removed). * This would have been set using the NG_NODE_REALLY_DIE(node) * macro in some device dependent function (not shown here) before * calling ng_rmnode_self(). */ static int ng_xxx_shutdown(node_p node) { const xxx_p privdata = NG_NODE_PRIVATE(node); #ifndef PERSISTANT_NODE NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); free(privdata, M_NETGRAPH); #else if (node->nd_flags & NGF_REALLY_DIE) { /* * WE came here because the widget card is being unloaded, * so stop being persistant. * Actually undo all the things we did on creation. */ NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(privdata->node); free(privdata, M_NETGRAPH); return (0); } NG_NODE_REVIVE(node); /* tell ng_rmnode() we will persist */ #endif /* PERSISTANT_NODE */ return (0); }
/* * Decode an incoming frame coming from the switch */ static int ngfrm_decode(node_p node, item_p item) { const sc_p sc = NG_NODE_PRIVATE(node); char *data; int alen; u_int dlci = 0; int error = 0; int ctxnum; struct mbuf *m; NGI_GET_M(item, m); if (m->m_len < 4 && (m = m_pullup(m, 4)) == NULL) { error = ENOBUFS; goto out; } data = mtod(m, char *); if ((alen = sc->addrlen) == 0) { sc->addrlen = alen = ngfrm_addrlen(data); } switch (alen) { case 2: SHIFTIN(makeup + 0, data[0], dlci); SHIFTIN(makeup + 1, data[1], dlci); break; case 3: SHIFTIN(makeup + 0, data[0], dlci); SHIFTIN(makeup + 1, data[1], dlci); SHIFTIN(makeup + 3, data[2], dlci); /* 3 and 2 is correct */ break; case 4: SHIFTIN(makeup + 0, data[0], dlci); SHIFTIN(makeup + 1, data[1], dlci); SHIFTIN(makeup + 2, data[2], dlci); SHIFTIN(makeup + 3, data[3], dlci); break; default: error = EINVAL; goto out; } if (dlci > 1023) { error = EINVAL; goto out; } ctxnum = sc->ALT[dlci]; if ((ctxnum & CTX_VALID) && sc->channel[ctxnum &= CTX_VALUE].hook) { /* Send it */ m_adj(m, alen); NG_FWD_NEW_DATA(error, item, sc->channel[ctxnum].hook, m); return (error); } else { error = ENETDOWN; } out: NG_FREE_ITEM(item); NG_FREE_M(m); return (error); }
/* * Receive data, and do something with it. * Actually we receive a queue item which holds the data. * If we free the item it will also free the data unless we have * previously disassociated it using the NGI_GET_M() macro. * Possibly send it out on another link after processing. * Possibly do something different if it comes from different * hooks. The caller will never free m, so if we use up this data or * abort we must free it. * * If we want, we may decide to force this data to be queued and reprocessed * at the netgraph NETISR time. * We would do that by setting the HK_QUEUE flag on our hook. We would do that * in the connect() method. */ static int ng_xxx_rcvdata(hook_p hook, item_p item ) { const xxx_p xxxp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); int chan = -2; int dlci = -2; int error; struct mbuf *m; NGI_GET_M(item, m); if (NG_HOOK_PRIVATE(hook)) { dlci = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->dlci; chan = ((struct XXX_hookinfo *) NG_HOOK_PRIVATE(hook))->channel; if (dlci != -1) { /* If received on a DLCI hook process for this * channel and pass it to the downstream module. * Normally one would add a multiplexing header at * the front here */ /* M_PREPEND(....) ; */ /* mtod(m, xxxxxx)->dlci = dlci; */ NG_FWD_NEW_DATA(error, item, xxxp->downstream_hook.hook, m); xxxp->packets_out++; } else { /* data came from the multiplexed link */ dlci = 1; /* get dlci from header */ /* madjust(....) *//* chop off header */ for (chan = 0; chan < XXX_NUM_DLCIS; chan++) if (xxxp->channel[chan].dlci == dlci) break; if (chan == XXX_NUM_DLCIS) { NG_FREE_ITEM(item); NG_FREE_M(m); return (ENETUNREACH); } /* If we were called at splnet, use the following: * NG_SEND_DATA_ONLY(error, otherhook, m); if this * node is running at some SPL other than SPLNET * then you should use instead: error = * ng_queueit(otherhook, m, NULL); m = NULL; * This queues the data using the standard NETISR * system and schedules the data to be picked * up again once the system has moved to SPLNET and * the processing of the data can continue. After * these are run 'm' should be considered * as invalid and NG_SEND_DATA actually zaps them. */ NG_FWD_NEW_DATA(error, item, xxxp->channel[chan].hook, m); xxxp->packets_in++; } } else { /* It's the debug hook, throw it away.. */ if (hook == xxxp->downstream_hook.hook) { NG_FREE_ITEM(item); NG_FREE_M(m); } } return 0; }
static int ng_ksocket_connect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); struct socket *const so = priv->so; /* Add our hook for incoming data and other events */ priv->so->so_upcallarg = (caddr_t)node; priv->so->so_upcall = ng_ksocket_incoming; SOCKBUF_LOCK(&priv->so->so_rcv); priv->so->so_rcv.sb_flags |= SB_UPCALL; SOCKBUF_UNLOCK(&priv->so->so_rcv); SOCKBUF_LOCK(&priv->so->so_snd); priv->so->so_snd.sb_flags |= SB_UPCALL; SOCKBUF_UNLOCK(&priv->so->so_snd); SOCK_LOCK(priv->so); sosetstate(priv->so, SS_NBIO); SOCK_UNLOCK(priv->so); /* * --Original comment-- * On a cloned socket we may have already received one or more * upcalls which we couldn't handle without a hook. Handle * those now. * We cannot call the upcall function directly * from here, because until this function has returned our * hook isn't connected. * * ---meta comment for -current --- * XXX This is dubius. * Upcalls between the time that the hook was * first created and now (on another processesor) will * be earlier on the queue than the request to finalise the hook. * By the time the hook is finalised, * The queued upcalls will have happenned and the code * will have discarded them because of a lack of a hook. * (socket not open). * * This is a bad byproduct of the complicated way in which hooks * are now created (3 daisy chained async events). * * Since we are a netgraph operation * We know that we hold a lock on this node. This forces the * request we make below to be queued rather than implemented * immediatly which will cause the upcall function to be called a bit * later. * However, as we will run any waiting queued operations immediatly * after doing this one, if we have not finalised the other end * of the hook, those queued operations will fail. */ if (priv->flags & KSF_CLONED) { ng_send_fn(node, NULL, &ng_ksocket_incoming2, so, M_WAITOK | M_NULLOK); } return (0); }
/* * Connect the data socket to a named control socket node. */ static int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) { struct sockaddr_ng *sap; node_p farnode; struct ngsock *priv; int error; item_p item; /* If we are already connected, don't do it again. */ if (pcbp->sockdata != NULL) return (EISCONN); /* * Find the target (victim) and check it doesn't already have * a data socket. Also check it is a 'socket' type node. * Use ng_package_data() and ng_address_path() to do this. */ sap = (struct sockaddr_ng *) nam; /* The item will hold the node reference. */ item = ng_package_data(NULL, NG_WAITOK); if ((error = ng_address_path(NULL, item, sap->sg_data, 0))) { ng_free_item(item); return (error); } /* * Extract node from item and free item. Remember we now have * a reference on the node. The item holds it for us. * when we free the item we release the reference. */ farnode = item->el_dest; /* shortcut */ if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { ng_free_item(item); /* drop the reference to the node */ return (EINVAL); } priv = NG_NODE_PRIVATE(farnode); if (priv->datasock != NULL) { ng_free_item(item); /* drop the reference to the node */ return (EADDRINUSE); } /* * Link the PCB and the private data struct. and note the extra * reference. Drop the extra reference on the node. */ mtx_lock(&priv->mtx); priv->datasock = pcbp; pcbp->sockdata = priv; priv->refs++; mtx_unlock(&priv->mtx); ng_free_item(item); /* drop the reference to the node */ return (0); }
/* * Shutdown node */ static int ngfrm_shutdown(node_p node) { const sc_p sc = NG_NODE_PRIVATE(node); NG_NODE_SET_PRIVATE(node, NULL); FREE(sc, M_NETGRAPH); NG_NODE_UNREF(node); return (0); }
/* * Do local shutdown processing.. * Cut any remaining links and free our local resources. */ static int nglmi_shutdown(node_p node) { const sc_p sc = NG_NODE_PRIVATE(node); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(sc->node); free(sc, M_NETGRAPH); return (0); }
static void bt3c_send(node_p node, hook_p hook, void *arg, int completed) { bt3c_softc_p sc = (bt3c_softc_p) NG_NODE_PRIVATE(node); struct mbuf *m = NULL; int i, wrote, len; if (sc == NULL) return; if (completed) sc->flags &= ~BT3C_XMIT; if (sc->flags & BT3C_XMIT) return; bt3c_set_address(sc, 0x7080); for (wrote = 0; wrote < BT3C_FIFO_SIZE; ) { IF_DEQUEUE(&sc->outq, m); if (m == NULL) break; while (m != NULL) { len = min((BT3C_FIFO_SIZE - wrote), m->m_len); for (i = 0; i < len; i++) bt3c_write_data(sc, m->m_data[i]); wrote += len; m->m_data += len; m->m_len -= len; if (m->m_len > 0) break; m = m_free(m); } if (m != NULL) { IF_PREPEND(&sc->outq, m); break; } NG_BT3C_STAT_PCKTS_SENT(sc->stat); } if (wrote > 0) { NG_BT3C_INFO(sc->dev, "Wrote %d bytes\n", wrote); NG_BT3C_STAT_BYTES_SENT(sc->stat, wrote); bt3c_write(sc, 0x7005, wrote); sc->flags |= BT3C_XMIT; } } /* bt3c_send */
/* * Flow control message from upper layer. * This is very experimental: * If we get a message from the upper layer, that somebody has passed its * high water mark, we stop updating the receive window. * If we get a low watermark passed, then we raise the window up * to max - current. * If we get a queue status and it indicates a current below the * high watermark, we unstop window updates (if they are stopped) and * raise the window to highwater - current. */ static int flow_upper(node_p node, struct ng_mesg *msg) { struct ngm_queue_state *q; struct priv *priv = NG_NODE_PRIVATE(node); u_int window, space; if (msg->header.arglen != sizeof(struct ngm_queue_state)) return (EINVAL); q = (struct ngm_queue_state *)msg->data; switch (msg->header.cmd) { case NGM_HIGH_WATER_PASSED: if (priv->flow) { VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, "flow control stopped")); priv->flow = 0; } break; case NGM_LOW_WATER_PASSED: window = sscop_window(priv->sscop, 0); space = q->max_queuelen_packets - q->current; if (space > window) { VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, "flow control opened window by %u messages", space - window)); (void)sscop_window(priv->sscop, space - window); } priv->flow = 1; break; case NGM_SYNC_QUEUE_STATE: if (q->high_watermark <= q->current) break; window = sscop_window(priv->sscop, 0); if (priv->flow) space = q->max_queuelen_packets - q->current; else space = q->high_watermark - q->current; if (space > window) { VERBOSE(priv, SSCOP_DBG_FLOW, (priv->sscop, priv, "flow control opened window by %u messages", space - window)); (void)sscop_window(priv->sscop, space - window); } priv->flow = 1; break; default: return (EINVAL); } return (0); }
static int ng_split_shutdown(node_p node) { const priv_p priv = NG_NODE_PRIVATE(node); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); free(priv, M_NETGRAPH); return (0); }
static int ng_vboxnetflt_shutdown(node_p node) { PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); bool fActive; /* Prevent node shutdown if we're active */ if (pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE) return (EBUSY); NG_NODE_UNREF(node); return (0); }
/* * Dook disconnection * * For this type, removal of the last link destroys the node */ Static int ng_udbp_disconnect(hook_p hook) { const udbp_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); sc->hook = NULL; if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) ng_rmnode_self(NG_HOOK_NODE(hook)); return (0); }
static int ng_ubt_connect(hook_p hook) { struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); UBT_NG_LOCK(sc); ubt_task_schedule(sc, UBT_FLAG_T_START_ALL); UBT_NG_UNLOCK(sc); return (0); } /* ng_ubt_connect */
/* * Get a netgraph control message. * We actually recieve a queue item that has a pointer to the message. * If we free the item, the message will be freed too, unless we remove * it from the item using NGI_GET_MSG(); * The return address is also stored in the item, as an ng_ID_t, * accessible as NGI_RETADDR(item); * Check it is one we understand. If needed, send a response. * We could save the address for an async action later, but don't here. * Always free the message. * The response should be in a malloc'd region that the caller can 'free'. * A response is not required. * Theoretically you could respond defferently to old message types if * the cookie in the header didn't match what we consider to be current * (so that old userland programs could continue to work). */ static int ng_xxx_rcvmsg(node_p node, item_p item, hook_p lasthook) { const xxx_p xxxp = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; int error = 0; struct ng_mesg *msg; NGI_GET_MSG(item, msg); /* Deal with message according to cookie and command */ switch (msg->header.typecookie) { case NGM_XXX_COOKIE: switch (msg->header.cmd) { case NGM_XXX_GET_STATUS: { struct ngxxxstat *stats; NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); if (!resp) { error = ENOMEM; break; } stats = (struct ngxxxstat *) resp->data; stats->packets_in = xxxp->packets_in; stats->packets_out = xxxp->packets_out; break; } case NGM_XXX_SET_FLAG: if (msg->header.arglen != sizeof(u_int32_t)) { error = EINVAL; break; } xxxp->flags = *((u_int32_t *) msg->data); break; default: error = EINVAL; /* unknown command */ break; } break; default: error = EINVAL; /* unknown cookie type */ break; } /* Take care of synchronous response, if any */ NG_RESPOND_MSG(error, node, item, resp); /* Free the message and return */ NG_FREE_MSG(msg); return(error); }
/* * If only one hook, allow read(2) and write(2) to work. */ static int ngs_connect(hook_p hook) { node_p node = NG_HOOK_NODE(hook); struct ngsock *priv = NG_NODE_PRIVATE(node); if ((priv->datasock) && (priv->datasock->ng_socket)) { if (NG_NODE_NUMHOOKS(node) == 1) sosetstate(priv->datasock->ng_socket, SS_ISCONNECTED); else soclrstate(priv->datasock->ng_socket, SS_ISCONNECTED); } return (0); }