diff options
author | Mat Martineau <mathewm@codeaurora.org> | 2012-04-11 13:48:43 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo@padovan.org> | 2012-05-09 00:40:31 -0400 |
commit | b76bbd6657a2dd7545686ba9ad59625f44192146 (patch) | |
tree | 8a7ea12a3688fefb53c997b715ee9a5629191693 /net/bluetooth/l2cap_core.c | |
parent | 3c588192b5e5328cdfc8e299c55477004d397208 (diff) |
Bluetooth: Functions for handling ERTM control fields
These functions encode or decode ERTM control fields (extended or
enhanced) to or from the new l2cap_ctrl structure.
Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
Acked-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/l2cap_core.c')
-rw-r--r-- | net/bluetooth/l2cap_core.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 041ebed9e647..913cec3e52d7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c | |||
@@ -786,6 +786,117 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) | |||
786 | l2cap_send_sframe(chan, control); | 786 | l2cap_send_sframe(chan, control); |
787 | } | 787 | } |
788 | 788 | ||
789 | static u16 __pack_enhanced_control(struct l2cap_ctrl *control) | ||
790 | { | ||
791 | u16 packed; | ||
792 | |||
793 | packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT; | ||
794 | packed |= control->final << L2CAP_CTRL_FINAL_SHIFT; | ||
795 | |||
796 | if (control->sframe) { | ||
797 | packed |= control->poll << L2CAP_CTRL_POLL_SHIFT; | ||
798 | packed |= control->super << L2CAP_CTRL_SUPER_SHIFT; | ||
799 | packed |= L2CAP_CTRL_FRAME_TYPE; | ||
800 | } else { | ||
801 | packed |= control->sar << L2CAP_CTRL_SAR_SHIFT; | ||
802 | packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT; | ||
803 | } | ||
804 | |||
805 | return packed; | ||
806 | } | ||
807 | |||
808 | static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control) | ||
809 | { | ||
810 | control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; | ||
811 | control->final = (enh & L2CAP_CTRL_FINAL) >> L2CAP_CTRL_FINAL_SHIFT; | ||
812 | |||
813 | if (enh & L2CAP_CTRL_FRAME_TYPE) { | ||
814 | /* S-Frame */ | ||
815 | control->sframe = 1; | ||
816 | control->poll = (enh & L2CAP_CTRL_POLL) >> L2CAP_CTRL_POLL_SHIFT; | ||
817 | control->super = (enh & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT; | ||
818 | |||
819 | control->sar = 0; | ||
820 | control->txseq = 0; | ||
821 | } else { | ||
822 | /* I-Frame */ | ||
823 | control->sframe = 0; | ||
824 | control->sar = (enh & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT; | ||
825 | control->txseq = (enh & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT; | ||
826 | |||
827 | control->poll = 0; | ||
828 | control->super = 0; | ||
829 | } | ||
830 | } | ||
831 | |||
832 | static u32 __pack_extended_control(struct l2cap_ctrl *control) | ||
833 | { | ||
834 | u32 packed; | ||
835 | |||
836 | packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT; | ||
837 | packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT; | ||
838 | |||
839 | if (control->sframe) { | ||
840 | packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT; | ||
841 | packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT; | ||
842 | packed |= L2CAP_EXT_CTRL_FRAME_TYPE; | ||
843 | } else { | ||
844 | packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT; | ||
845 | packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT; | ||
846 | } | ||
847 | |||
848 | return packed; | ||
849 | } | ||
850 | |||
851 | static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control) | ||
852 | { | ||
853 | control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT; | ||
854 | control->final = (ext & L2CAP_EXT_CTRL_FINAL) >> L2CAP_EXT_CTRL_FINAL_SHIFT; | ||
855 | |||
856 | if (ext & L2CAP_EXT_CTRL_FRAME_TYPE) { | ||
857 | /* S-Frame */ | ||
858 | control->sframe = 1; | ||
859 | control->poll = (ext & L2CAP_EXT_CTRL_POLL) >> L2CAP_EXT_CTRL_POLL_SHIFT; | ||
860 | control->super = (ext & L2CAP_EXT_CTRL_SUPERVISE) >> L2CAP_EXT_CTRL_SUPER_SHIFT; | ||
861 | |||
862 | control->sar = 0; | ||
863 | control->txseq = 0; | ||
864 | } else { | ||
865 | /* I-Frame */ | ||
866 | control->sframe = 0; | ||
867 | control->sar = (ext & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT; | ||
868 | control->txseq = (ext & L2CAP_EXT_CTRL_TXSEQ) >> L2CAP_EXT_CTRL_TXSEQ_SHIFT; | ||
869 | |||
870 | control->poll = 0; | ||
871 | control->super = 0; | ||
872 | } | ||
873 | } | ||
874 | |||
875 | static inline void __unpack_control(struct l2cap_chan *chan, | ||
876 | struct sk_buff *skb) | ||
877 | { | ||
878 | if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { | ||
879 | __unpack_extended_control(get_unaligned_le32(skb->data), | ||
880 | &bt_cb(skb)->control); | ||
881 | } else { | ||
882 | __unpack_enhanced_control(get_unaligned_le16(skb->data), | ||
883 | &bt_cb(skb)->control); | ||
884 | } | ||
885 | } | ||
886 | |||
887 | static inline void __pack_control(struct l2cap_chan *chan, | ||
888 | struct l2cap_ctrl *control, | ||
889 | struct sk_buff *skb) | ||
890 | { | ||
891 | if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { | ||
892 | put_unaligned_le32(__pack_extended_control(control), | ||
893 | skb->data + L2CAP_HDR_SIZE); | ||
894 | } else { | ||
895 | put_unaligned_le16(__pack_enhanced_control(control), | ||
896 | skb->data + L2CAP_HDR_SIZE); | ||
897 | } | ||
898 | } | ||
899 | |||
789 | static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) | 900 | static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) |
790 | { | 901 | { |
791 | return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); | 902 | return !test_bit(CONF_CONNECT_PEND, &chan->conf_state); |
@@ -4359,6 +4470,8 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) | |||
4359 | u16 req_seq; | 4470 | u16 req_seq; |
4360 | int len, next_tx_seq_offset, req_seq_offset; | 4471 | int len, next_tx_seq_offset, req_seq_offset; |
4361 | 4472 | ||
4473 | __unpack_control(chan, skb); | ||
4474 | |||
4362 | control = __get_control(chan, skb->data); | 4475 | control = __get_control(chan, skb->data); |
4363 | skb_pull(skb, __ctrl_size(chan)); | 4476 | skb_pull(skb, __ctrl_size(chan)); |
4364 | len = skb->len; | 4477 | len = skb->len; |