/* * 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; }
/* * Receive data */ static int ngee_rcvdata(hook_p hook, item_p item) { int error; struct mbuf *m; struct ether_header *eh; struct ether_addr tmpaddr; /* Make sure we have an entire header */ NGI_GET_M(item, m); if (m->m_len < sizeof(*eh) ) { m = m_pullup(m, sizeof(*eh)); if (m == NULL) { NG_FREE_ITEM(item); return(EINVAL); } } eh = mtod(m, struct ether_header *); /* swap the source and destination fields */ bcopy(eh->ether_dhost, &tmpaddr, ETHER_ADDR_LEN); bcopy(eh->ether_shost, eh->ether_dhost, ETHER_ADDR_LEN); bcopy(&tmpaddr, eh->ether_shost, ETHER_ADDR_LEN); NG_FWD_NEW_DATA(error, item, hook, m); return (error); }
/* * 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 packet */ static int ngfrm_rcvdata(hook_p hook, item_p item) { struct ctxinfo *const ctxp = NG_HOOK_PRIVATE(hook); int error = 0; int dlci; sc_p sc; int alen; char *data; struct mbuf *m; /* Data doesn't come in from just anywhere (e.g debug hook) */ if (ctxp == NULL) { error = ENETDOWN; goto bad; } /* If coming from downstream, decode it to a channel */ dlci = ctxp->dlci; if (dlci == -1) return (ngfrm_decode(NG_HOOK_NODE(hook), item)); NGI_GET_M(item, m); /* Derive the softc we will need */ sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); /* If there is no live channel, throw it away */ if ((sc->downstream.hook == NULL) || ((ctxp->flags & CHAN_ACTIVE) == 0)) { error = ENETDOWN; goto bad; } /* Store the DLCI on the front of the packet */ alen = sc->addrlen; if (alen == 0) alen = 2; /* default value for transmit */ M_PREPEND(m, alen, M_DONTWAIT); if (m == NULL) { error = ENOBUFS; goto bad; } data = mtod(m, char *); /* * Shift the lowest bits into the address field untill we are done. * First byte is MSBits of addr so work backwards. */ switch (alen) { case 2: data[0] = data[1] = '\0'; SHIFTOUT(makeup + 1, data[1], dlci); SHIFTOUT(makeup + 0, data[0], dlci); data[1] |= BYTEX_EA; break; case 3: data[0] = data[1] = data[2] = '\0'; SHIFTOUT(makeup + 3, data[2], dlci); /* 3 and 2 is correct */ SHIFTOUT(makeup + 1, data[1], dlci); SHIFTOUT(makeup + 0, data[0], dlci); data[2] |= BYTEX_EA; break; case 4: data[0] = data[1] = data[2] = data[3] = '\0'; SHIFTOUT(makeup + 3, data[3], dlci); SHIFTOUT(makeup + 2, data[2], dlci); SHIFTOUT(makeup + 1, data[1], dlci); SHIFTOUT(makeup + 0, data[0], dlci); data[3] |= BYTEX_EA; break; default: panic(__func__); } /* Send it */ NG_FWD_NEW_DATA(error, item, sc->downstream.hook, m); return (error); bad: NG_FREE_ITEM(item); NG_FREE_M(m); return (error); }