예제 #1
0
파일: l2cap.c 프로젝트: cyysu/AliOS-Things
static void l2cap_chan_le_recv_sdu(struct bt_l2cap_le_chan *chan,
				   struct net_buf *buf)
{
	struct net_buf *frag;
	uint16_t len;

	BT_DBG("chan %p len %u sdu %zu", chan, buf->len,
	       net_buf_frags_len(chan->_sdu));

	if (net_buf_frags_len(chan->_sdu) + buf->len > chan->_sdu_len) {
		BT_ERR("SDU length mismatch");
		bt_l2cap_chan_disconnect(&chan->chan);
		return;
	}

	/* Jump to last fragment */
	frag = net_buf_frag_last(chan->_sdu);

	while (buf->len) {
		/* Check if there is any space left in the current fragment */
		if (!net_buf_tailroom(frag)) {
			frag = l2cap_alloc_frag(chan);
			if (!frag) {
				BT_ERR("Unable to store SDU");
				bt_l2cap_chan_disconnect(&chan->chan);
				return;
			}
		}

		len = min(net_buf_tailroom(frag), buf->len);
		net_buf_add_mem(frag, buf->data, len);
		net_buf_pull(buf, len);

		BT_DBG("frag %p len %u", frag, frag->len);
	}

	if (net_buf_frags_len(chan->_sdu) == chan->_sdu_len) {
		/* Receiving complete SDU, notify channel and reset SDU buf */
		chan->chan.ops->recv(&chan->chan, chan->_sdu);
		net_buf_unref(chan->_sdu);
		chan->_sdu = NULL;
		chan->_sdu_len = 0;
	}

	l2cap_chan_update_credits(chan);
}
예제 #2
0
파일: l2cap.c 프로젝트: hudkmr/zephyr
static void l2cap_chan_le_recv(struct bt_l2cap_le_chan *chan,
			       struct net_buf *buf)
{
	uint16_t sdu_len;

	if (!nano_fiber_sem_take(&chan->rx.credits, TICKS_NONE)) {
		BT_ERR("No credits to receive packet");
		bt_l2cap_chan_disconnect(&chan->chan);
		return;
	}

	/* Check if segments already exist */
	if (chan->_sdu) {
		l2cap_chan_le_recv_sdu(chan, buf);
		return;
	}

	sdu_len = net_buf_pull_le16(buf);

	BT_DBG("chan %p len %u sdu_len %u", chan, buf->len, sdu_len);

	if (sdu_len > chan->rx.mtu) {
		BT_ERR("Invalid SDU length");
		bt_l2cap_chan_disconnect(&chan->chan);
		return;
	}

	/* Always allocate buffer from the channel if supported. */
	if (chan->chan.ops && chan->chan.ops->alloc_buf) {
		chan->_sdu = chan->chan.ops->alloc_buf(&chan->chan);
		if (!chan->_sdu) {
			BT_ERR("Unable to allocate buffer for SDU");
			bt_l2cap_chan_disconnect(&chan->chan);
			return;
		}
		chan->_sdu_len = sdu_len;
		l2cap_chan_le_recv_sdu(chan, buf);
		return;
	}

	chan->chan.ops->recv(&chan->chan, buf);

	l2cap_chan_update_credits(chan);
}
예제 #3
0
파일: bluetooth.c 프로젝트: bboozzoo/zephyr
static int bt_disconnect(u32_t mgmt_request, struct net_if *iface,
			 void *data, size_t len)
{
	struct bt_context *ctxt = net_if_get_device(iface)->driver_data;

	if (!ctxt->ipsp_chan.chan.conn) {
		NET_ERR("Not connected");
		return -ENOTCONN;
	}

	/* Release connect reference in case of central/router role */
	if (default_conn) {
		bt_conn_unref(default_conn);
		default_conn = NULL;
	}

	return bt_l2cap_chan_disconnect(&ctxt->ipsp_chan.chan);
}
예제 #4
0
파일: l2cap.c 프로젝트: cyysu/AliOS-Things
static void le_credits(struct bt_l2cap *l2cap, uint8_t ident,
		       struct net_buf *buf)
{
	struct bt_conn *conn = l2cap->chan.chan.conn;
	struct bt_l2cap_chan *chan;
	struct bt_l2cap_le_credits *ev = (void *)buf->data;
	struct bt_l2cap_le_chan *ch;
	uint16_t credits, cid;

	if (buf->len < sizeof(*ev)) {
		BT_ERR("Too small LE Credits packet size");
		return;
	}

	cid = sys_le16_to_cpu(ev->cid);
	credits = sys_le16_to_cpu(ev->credits);

	BT_DBG("cid 0x%04x credits %u", cid, credits);

	chan = bt_l2cap_le_lookup_tx_cid(conn, cid);
	if (!chan) {
		BT_ERR("Unable to find channel of LE Credits packet");
		return;
	}

	ch = BT_L2CAP_LE_CHAN(chan);

	if (k_sem_count_get(&ch->tx.credits) + credits > UINT16_MAX) {
		BT_ERR("Credits overflow");
		bt_l2cap_chan_disconnect(chan);
		return;
	}

	l2cap_chan_tx_give_credits(ch, credits);

	BT_DBG("chan %p total credits %u", ch,
	       k_sem_count_get(&ch->tx.credits));

	l2cap_chan_le_send_resume(ch);
}
예제 #5
0
파일: l2cap.c 프로젝트: hudkmr/zephyr
static void l2cap_chan_le_recv_sdu(struct bt_l2cap_le_chan *chan,
				   struct net_buf *buf)
{
	BT_DBG("chan %p len %u sdu len %u", chan, buf->len, chan->_sdu->len);

	if (chan->_sdu->len + buf->len > chan->_sdu_len) {
		BT_ERR("SDU length mismatch");
		bt_l2cap_chan_disconnect(&chan->chan);
		return;
	}

	memcpy(net_buf_add(chan->_sdu, buf->len), buf->data, buf->len);

	if (chan->_sdu->len == chan->_sdu_len) {
		/* Receiving complete SDU, notify channel and reset SDU buf */
		chan->chan.ops->recv(&chan->chan, chan->_sdu);
		net_buf_unref(chan->_sdu);
		chan->_sdu = NULL;
		chan->_sdu_len = 0;
	}

	l2cap_chan_update_credits(chan);
}