/* * 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); }
/* * 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_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)); }
/* * 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); }
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); }
/* * 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; }
/* * Receive data */ static int ngipi_rcvdata(hook_p hook, item_p item) { struct mbuf *m; NGI_GET_M(item, m); NG_FREE_ITEM(item); if (curthread->td_ng_outbound) netisr_queue(NETISR_IP, m); else netisr_dispatch(NETISR_IP, m); return 0; }
/* * Receive data */ static int ng_vjc_rcvdata(hook_p hook, item_p item) { const node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); int error = 0; struct mbuf *m; NGI_GET_M(item, m); if (hook == priv->ip) { /* outgoing packet */ u_int type = TYPE_IP; /* Compress packet if enabled and proto is TCP */ if (priv->conf.enableComp) { struct ip *ip; if ((m = ng_vjc_pulluphdrs(m, 0)) == NULL) { NG_FREE_ITEM(item); return (ENOBUFS); } ip = mtod(m, struct ip *); if (ip->ip_p == IPPROTO_TCP) { const int origLen = m->m_len; type = sl_compress_tcp(m, ip, &priv->slc, priv->conf.compressCID); m->m_pkthdr.len += m->m_len - origLen; } } /* Dispatch to the appropriate outgoing hook */ switch (type) { case TYPE_IP: hook = priv->vjip; break; case TYPE_UNCOMPRESSED_TCP: hook = priv->vjuncomp; break; case TYPE_COMPRESSED_TCP: hook = priv->vjcomp; break; default: panic("%s: type=%d", __func__, type); } } else if (hook == priv->vjcomp) { /* incoming compressed packet */
/* * Accept data from the hook and queue it for output. */ Static int ng_udbp_rcvdata(hook_p hook, item_p item) { const udbp_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); int error; struct ifqueue *xmitq_p; int s; struct mbuf *m; meta_p meta; NGI_GET_M(item, m); NGI_GET_META(item, meta); NG_FREE_ITEM(item); /* * Now queue the data for when it can be sent */ if (meta && meta->priority > 0) { xmitq_p = (&sc->xmitq_hipri); } else { xmitq_p = (&sc->xmitq); } s = splusb(); IF_LOCK(xmitq_p); if (_IF_QFULL(xmitq_p)) { _IF_DROP(xmitq_p); IF_UNLOCK(xmitq_p); splx(s); error = ENOBUFS; goto bad; } _IF_ENQUEUE(xmitq_p, m); IF_UNLOCK(xmitq_p); if (!(sc->flags & OUT_BUSY)) udbp_setup_out_transfer(sc); splx(s); return (0); bad: /* * It was an error case. * check if we need to free the mbuf, and then return the error */ NG_FREE_M(m); NG_FREE_META(meta); return (error); }
static int ng_btsocket_hci_raw_node_rcvdata(hook_p hook, item_p item) { struct mbuf *nam = NULL; int error; /* * Check for empty sockets list creates LOR when both sender and * receiver device are connected to the same host, so remove it * for now */ MGET(nam, M_NOWAIT, MT_SONAME); if (nam != NULL) { struct sockaddr_hci *sa = mtod(nam, struct sockaddr_hci *); nam->m_len = sizeof(struct sockaddr_hci); sa->hci_len = sizeof(*sa); sa->hci_family = AF_BLUETOOTH; strlcpy(sa->hci_node, NG_PEER_NODE_NAME(hook), sizeof(sa->hci_node)); NGI_GET_M(item, nam->m_next); NGI_M(item) = nam; lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_EXCLUSIVE); if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) { NG_BTSOCKET_HCI_RAW_ERR( "%s: Input queue is full\n", __func__); NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue); NG_FREE_ITEM(item); error = ENOBUFS; } else { ng_ref_item(item); NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item); error = ng_btsocket_hci_raw_wakeup_input_task(); } lockmgr(&ng_btsocket_hci_raw_queue_lock, LK_RELEASE); } else {
static int ng_sscop_rcvmanage(hook_p hook, item_p item) { struct priv *priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct sscop_marg a; struct mbuf *m; if (!priv->enabled) { NG_FREE_ITEM(item); return (EINVAL); } NGI_GET_M(item, m); NG_FREE_ITEM(item); 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_maasig(priv->sscop, a.sig, m)); }
/* * Receive data on a hook */ static int ngs_rcvdata(hook_p hook, item_p item) { struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct ngpcb *const pcbp = priv->datasock; struct socket *so; struct sockaddr_ng *addr; char *addrbuf[NG_HOOKSIZ + 4]; int addrlen; struct mbuf *m; NGI_GET_M(item, m); NG_FREE_ITEM(item); /* If there is no data socket, black-hole it. */ if (pcbp == NULL) { NG_FREE_M(m); return (0); } so = pcbp->ng_socket; /* Get the return address into a sockaddr. */ addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKSIZ - 1 */ addr = (struct sockaddr_ng *) addrbuf; addr->sg_len = addrlen + 3; addr->sg_family = AF_NETGRAPH; bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); addr->sg_data[addrlen] = '\0'; /* Try to tell the socket which hook it came in on. */ if (sbappendaddr((struct sockbuf *)&so->so_rcv, (struct sockaddr *)addr, m, NULL) == 0) { m_freem(m); TRAP_ERROR; return (ENOBUFS); } sorwakeup(so); return (0); }
static int ng_bt3c_rcvdata(hook_p hook, item_p item) { bt3c_softc_p sc = (bt3c_softc_p)NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct mbuf *m = NULL; int error = 0; if (sc == NULL) { error = EHOSTDOWN; goto out; } if (hook != sc->hook) { error = EINVAL; goto out; } NGI_GET_M(item, m); IF_LOCK(&sc->outq); if (_IF_QFULL(&sc->outq)) { NG_BT3C_ERR(sc->dev, "Outgoing queue is full. Dropping mbuf, len=%d\n", m->m_pkthdr.len); _IF_DROP(&sc->outq); NG_BT3C_STAT_OERROR(sc->stat); NG_FREE_M(m); } else _IF_ENQUEUE(&sc->outq, m); IF_UNLOCK(&sc->outq); error = ng_send_fn(sc->node, NULL, bt3c_send, NULL, 0 /* new send */); out: NG_FREE_ITEM(item); return (error); } /* ng_bt3c_rcvdata */
/** * Handle data on netgraph hooks. * Frames processing is deferred to a taskqueue because this might * be called with non-sleepable locks held and code paths inside * the virtual switch might sleep. */ static int ng_vboxnetflt_rcvdata(hook_p hook, item_p item) { const node_p node = NG_HOOK_NODE(hook); PVBOXNETFLTINS pThis = NG_NODE_PRIVATE(node); struct ifnet *ifp = pThis->u.s.ifp; struct mbuf *m; struct m_tag *mtag; bool fActive; VBOXCURVNET_SET(ifp->if_vnet); fActive = vboxNetFltTryRetainBusyActive(pThis); NGI_GET_M(item, m); NG_FREE_ITEM(item); /* Locate tag to see if processing should be skipped for this frame */ mtag = m_tag_locate(m, MTAG_VBOX, PACKET_TAG_VBOX, NULL); if (mtag != NULL) { m_tag_unlink(m, mtag); m_tag_free(mtag); } /* * Handle incoming hook. This is connected to the * input path of the interface, thus handling incoming frames. */ if (pThis->u.s.input == hook) { if (mtag != NULL || !fActive) { ether_demux(ifp, m); if (fActive) vboxNetFltRelease(pThis, true /*fBusy*/); VBOXCURVNET_RESTORE(); return (0); } mtx_lock_spin(&pThis->u.s.inq.ifq_mtx); _IF_ENQUEUE(&pThis->u.s.inq, m); mtx_unlock_spin(&pThis->u.s.inq.ifq_mtx); taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskin); } /* * Handle mbufs on the outgoing hook, frames going to the interface */ else if (pThis->u.s.output == hook) { if (mtag != NULL || !fActive) { int rc = ether_output_frame(ifp, m); if (fActive) vboxNetFltRelease(pThis, true /*fBusy*/); VBOXCURVNET_RESTORE(); return rc; } mtx_lock_spin(&pThis->u.s.outq.ifq_mtx); _IF_ENQUEUE(&pThis->u.s.outq, m); mtx_unlock_spin(&pThis->u.s.outq.ifq_mtx); taskqueue_enqueue_fast(taskqueue_fast, &pThis->u.s.tskout); } else { m_freem(m); } if (fActive) vboxNetFltRelease(pThis, true /*fBusy*/); VBOXCURVNET_RESTORE(); return (0); }
static int ng_vlan_rcvdata(hook_p hook, item_p item) { const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct ether_header *eh; struct ether_vlan_header *evl; int error; uintptr_t hook_data; uint16_t vid, eth_vtag; struct mbuf *m; hook_p dst_hook; NGI_GET_M(item, m); /* Make sure we have an entire header. */ error = m_chk(&m, ETHER_HDR_LEN); if (error != 0) goto mchk_err; eh = mtod(m, struct ether_header *); if (hook == priv->downstream_hook) { /* * If from downstream, select between a match hook * or the nomatch hook. */ dst_hook = priv->nomatch_hook; /* Skip packets without tag. */ if ((m->m_flags & M_VLANTAG) == 0 && eh->ether_type != priv->encap_proto) { if (dst_hook == NULL) goto net_down; goto send_packet; } /* Process packets with tag. */ if (m->m_flags & M_VLANTAG) { /* * Packet is tagged, m contains a normal * Ethernet frame; tag is stored out-of-band. */ evl = NULL; vid = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag); } else { /* eh->ether_type == priv->encap_proto */ error = m_chk(&m, ETHER_VLAN_HDR_LEN); if (error != 0) goto mchk_err; evl = mtod(m, struct ether_vlan_header *); vid = EVL_VLANOFTAG(ntohs(evl->evl_tag)); } if (priv->vlan_hook[vid] != NULL) { /* * VLAN filter: allways remove vlan tags and * decapsulate packet. */ dst_hook = priv->vlan_hook[vid]; if (evl == NULL) { /* m->m_flags & M_VLANTAG */ m->m_pkthdr.ether_vtag = 0; m->m_flags &= ~M_VLANTAG; goto send_packet; } } else { /* nomatch_hook */ if (dst_hook == NULL) goto net_down; if (evl == NULL || priv->decap_enable == 0) goto send_packet; /* Save tag out-of-band. */ m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag); m->m_flags |= M_VLANTAG; } /* * Decapsulate: * TPID = ether type encap * Move DstMAC and SrcMAC to ETHER_TYPE. * Before: * [dmac] [smac] [TPID] [PCP/CFI/VID] [ether_type] [payload] * |-----------| >>>>>>>>>>>>>>>>>>>> |--------------------| * After: * [free space ] [dmac] [smac] [ether_type] [payload] * |-----------| |--------------------| */ bcopy((char *)evl, ((char *)evl + ETHER_VLAN_ENCAP_LEN), (ETHER_ADDR_LEN * 2)); m_adj(m, ETHER_VLAN_ENCAP_LEN); } else {
/* * receive data, and use it to update our status. * Anything coming in on the debug port is discarded. */ static int nglmi_rcvdata(hook_p hook, item_p item) { sc_p sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); const u_char *data; unsigned short dlci; u_short packetlen; int resptype_seen = 0; struct mbuf *m; NGI_GET_M(item, m); NG_FREE_ITEM(item); if (NG_HOOK_PRIVATE(hook) == NULL) { goto drop; } packetlen = m->m_len; /* XXX what if it's more than 1 mbuf? */ if ((packetlen > MHLEN) && !(m->m_flags & M_EXT)) { log(LOG_WARNING, "nglmi: packetlen (%d) too big\n", packetlen); goto drop; } if (m->m_len < packetlen && (m = m_pullup(m, packetlen)) == NULL) { log(LOG_WARNING, "nglmi: m_pullup failed for %d bytes\n", packetlen); return (0); } if (nglmi_checkdata(hook, m) == 0) return (0); /* pass the first 4 bytes (already checked in the nglmi_checkdata()) */ data = mtod(m, const u_char *); STEPBY(4); /* Now check if there is a 'locking shift'. This is only seen in * Annex D frames. don't bother checking, we already did that. Don't * increment immediatly as it might not be there. */ if (ANNEXD(sc)) STEPBY(1); /* If we get this far we should consider that it is a legitimate * frame and we know what it is. */ if (sc->flags & SCF_AUTO) { /* note the hook that this valid channel came from and drop * out of auto probe mode. */ if (ANNEXA(sc)) sc->protoname = NAME_ANNEXA; else if (ANNEXD(sc)) sc->protoname = NAME_ANNEXD; else if (GROUP4(sc)) sc->protoname = NAME_GROUP4; else { log(LOG_ERR, "nglmi: No known type\n"); goto drop; } sc->lmi_channel = hook; sc->flags &= ~SCF_AUTO; log(LOG_INFO, "nglmi: auto-detected %s LMI on DLCI %d\n", sc->protoname, hook == sc->lmi_channel0 ? 0 : 1023); } /* While there is more data in the status packet, keep processing * status items. First make sure there is enough data for the * segment descriptor's length field. */ while (packetlen >= 2) { u_int segtype = data[0]; u_int segsize = data[1]; /* Now that we know how long it claims to be, make sure * there is enough data for the next seg. */ if (packetlen < segsize + 2) break; switch (segtype) { case 0x01: case 0x51: if (resptype_seen) { log(LOG_WARNING, "nglmi: dup MSGTYPE\n"); goto nextIE; } resptype_seen++; /* The remote end tells us what kind of response * this is. Only expect a type 0 or 1. if we are a * full status, invalidate a few DLCIs just to see * that they are still ok. */ if (segsize != 1) goto nextIE; switch (data[2]) { case 1: /* partial status, do no extra processing */ break; case 0: { int count = 0; int idx = sc->invalidx; for (count = 0; count < 10; count++) { if (idx > MAXDLCI) idx = 0; if (sc->dlci_state[idx] == DLCI_UP) sc->dlci_state[idx] = DLCI_DOWN; idx++; } sc->invalidx = idx; /* we got and we wanted one. relax * now.. but don't reset to 0 if it * was unrequested. */ if (sc->livs > sc->liv_per_full) sc->livs = 0; break; } } break; case 0x03: case 0x53: /* The remote tells us what it thinks the sequence * numbers are. If it's not size 2, it must be a * duplicate to have gotten this far, skip it. */ if (segsize != 2) goto nextIE; sc->remote_seq = data[2]; if (sc->local_seq == data[3]) { sc->local_seq++; sc->seq_retries = 0; /* Note that all 3 Frame protocols seem to * not like 0 as a sequence number. */ if (sc->local_seq == 0) sc->local_seq = 1; } break; case 0x07: case 0x57: /* The remote tells us about a DLCI that it knows * about. There may be many of these in a single * status response */ switch (segsize) { case 6:/* only on 'group of 4' */ dlci = ((u_short) data[2] & 0xff) << 8; dlci |= (data[3] & 0xff); if ((dlci < 1024) && (dlci > 0)) { /* XXX */ } break; case 3: dlci = ((u_short) data[2] & 0x3f) << 4; dlci |= ((data[3] & 0x78) >> 3); if ((dlci < 1024) && (dlci > 0)) { /* set up the bottom half of the * support for that dlci if it's not * already been done */ /* store this information somewhere */ } break; default: goto nextIE; } if (sc->dlci_state[dlci] != DLCI_UP) { /* bring new DLCI to life */ /* may do more here some day */ if (sc->dlci_state[dlci] != DLCI_DOWN) log(LOG_INFO, "nglmi: DLCI %d became active\n", dlci); sc->dlci_state[dlci] = DLCI_UP; } break; } nextIE: STEPBY(segsize + 2); } NG_FREE_M(m); return (0); drop: NG_FREE_M(m); return (EINVAL); }
static int ng_ubt_rcvdata(hook_p hook, item_p item) { struct ubt_softc *sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct mbuf *m; struct ng_bt_mbufq *q; int action, error = 0; if (hook != sc->sc_hook) { error = EINVAL; goto done; } /* Deatch mbuf and get HCI frame type */ NGI_GET_M(item, m); /* * Minimal size of the HCI frame is 4 bytes: 1 byte frame type, * 2 bytes connection handle and at least 1 byte of length. * Panic on data frame that has size smaller than 4 bytes (it * should not happen) */ if (m->m_pkthdr.len < 4) panic("HCI frame size is too small! pktlen=%d\n", m->m_pkthdr.len); /* Process HCI frame */ switch (*mtod(m, uint8_t *)) { /* XXX call m_pullup ? */ case NG_HCI_CMD_PKT: if (m->m_pkthdr.len - 1 > (int)UBT_CTRL_BUFFER_SIZE) panic("HCI command frame size is too big! " \ "buffer size=%zd, packet len=%d\n", UBT_CTRL_BUFFER_SIZE, m->m_pkthdr.len); q = &sc->sc_cmdq; action = UBT_FLAG_T_START_CTRL; break; case NG_HCI_ACL_DATA_PKT: if (m->m_pkthdr.len - 1 > UBT_BULK_WRITE_BUFFER_SIZE) panic("ACL data frame size is too big! " \ "buffer size=%d, packet len=%d\n", UBT_BULK_WRITE_BUFFER_SIZE, m->m_pkthdr.len); q = &sc->sc_aclq; action = UBT_FLAG_T_START_BULK; break; case NG_HCI_SCO_DATA_PKT: q = &sc->sc_scoq; action = 0; break; default: UBT_ERR(sc, "Dropping unsupported HCI frame, type=0x%02x, " \ "pktlen=%d\n", *mtod(m, uint8_t *), m->m_pkthdr.len); NG_FREE_M(m); error = EINVAL; goto done; /* NOT REACHED */ } UBT_NG_LOCK(sc); if (NG_BT_MBUFQ_FULL(q)) { NG_BT_MBUFQ_DROP(q); UBT_NG_UNLOCK(sc); UBT_ERR(sc, "Dropping HCI frame 0x%02x, len=%d. Queue full\n", *mtod(m, uint8_t *), m->m_pkthdr.len); NG_FREE_M(m); } else {
/* * 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); }