diff options
author | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-04-28 17:50:17 -0400 |
---|---|---|
committer | Gustavo F. Padovan <padovan@profusion.mobi> | 2011-06-08 15:58:16 -0400 |
commit | 9a91a04a95d30a18909e2aec9d7b17b4c86088a7 (patch) | |
tree | e0c260031fe79ceaa8cb858b7316ce43974cef08 /net/bluetooth/l2cap_core.c | |
parent | 4519de9a0478d8de438f8b80ab2e94668ef63ab4 (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.c | 80 |
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 | ||
1538 | int 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 | |||
1538 | static void l2cap_chan_ready(struct sock *sk) | 1618 | static 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; |