aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/l2cap_core.c
diff options
context:
space:
mode:
authorGustavo F. Padovan <padovan@profusion.mobi>2011-04-28 17:50:17 -0400
committerGustavo F. Padovan <padovan@profusion.mobi>2011-06-08 15:58:16 -0400
commit9a91a04a95d30a18909e2aec9d7b17b4c86088a7 (patch)
treee0c260031fe79ceaa8cb858b7316ce43974cef08 /net/bluetooth/l2cap_core.c
parent4519de9a0478d8de438f8b80ab2e94668ef63ab4 (diff)
Bluetooth: Create l2cap_chan_send()
This move all the sending logic to l2cap_core.c, but we still have a socket dependence there, struct msghdr. It will be removed in some of the further commits. Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r--net/bluetooth/l2cap_core.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 14c760c8ffe7..e65f63130113 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1535,6 +1535,86 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le
1535 return size; 1535 return size;
1536} 1536}
1537 1537
1538int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1539{
1540 struct sock *sk = chan->sk;
1541 struct sk_buff *skb;
1542 u16 control;
1543 int err;
1544
1545 /* Connectionless channel */
1546 if (sk->sk_type == SOCK_DGRAM) {
1547 skb = l2cap_create_connless_pdu(chan, msg, len);
1548 if (IS_ERR(skb))
1549 return PTR_ERR(skb);
1550
1551 l2cap_do_send(chan, skb);
1552 return len;
1553 }
1554
1555 switch (chan->mode) {
1556 case L2CAP_MODE_BASIC:
1557 /* Check outgoing MTU */
1558 if (len > chan->omtu)
1559 return -EMSGSIZE;
1560
1561 /* Create a basic PDU */
1562 skb = l2cap_create_basic_pdu(chan, msg, len);
1563 if (IS_ERR(skb))
1564 return PTR_ERR(skb);
1565
1566 l2cap_do_send(chan, skb);
1567 err = len;
1568 break;
1569
1570 case L2CAP_MODE_ERTM:
1571 case L2CAP_MODE_STREAMING:
1572 /* Entire SDU fits into one PDU */
1573 if (len <= chan->remote_mps) {
1574 control = L2CAP_SDU_UNSEGMENTED;
1575 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1576 0);
1577 if (IS_ERR(skb))
1578 return PTR_ERR(skb);
1579
1580 __skb_queue_tail(&chan->tx_q, skb);
1581
1582 if (chan->tx_send_head == NULL)
1583 chan->tx_send_head = skb;
1584
1585 } else {
1586 /* Segment SDU into multiples PDUs */
1587 err = l2cap_sar_segment_sdu(chan, msg, len);
1588 if (err < 0)
1589 return err;
1590 }
1591
1592 if (chan->mode == L2CAP_MODE_STREAMING) {
1593 l2cap_streaming_send(chan);
1594 err = len;
1595 break;
1596 }
1597
1598 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1599 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1600 err = len;
1601 break;
1602 }
1603
1604 err = l2cap_ertm_send(chan);
1605 if (err >= 0)
1606 err = len;
1607
1608 break;
1609
1610 default:
1611 BT_DBG("bad state %1.1x", chan->mode);
1612 err = -EBADFD;
1613 }
1614
1615 return err;
1616}
1617
1538static void l2cap_chan_ready(struct sock *sk) 1618static void l2cap_chan_ready(struct sock *sk)
1539{ 1619{
1540 struct sock *parent = bt_sk(sk)->parent; 1620 struct sock *parent = bt_sk(sk)->parent;