diff options
author | Suraj Sumangala <suraj@atheros.com> | 2010-07-14 03:32:17 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-07-21 13:39:12 -0400 |
commit | 33e882a5f2301a23a85ef2994e30fd9f48d39d9b (patch) | |
tree | 4048a954d11698581e123b25389a9f8f72125f90 /net/bluetooth | |
parent | cd4c53919ed50b0d532f106aeb76e79077bece98 (diff) |
Bluetooth: Implement hci_reassembly helper to reassemble RX packets
Implements feature to reassemble received HCI frames from any input stream
Signed-off-by: Suraj Sumangala <suraj@atheros.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_core.c | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 0ded790bfb67..477c4a60a079 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -1033,6 +1033,115 @@ int hci_recv_frame(struct sk_buff *skb) | |||
1033 | } | 1033 | } |
1034 | EXPORT_SYMBOL(hci_recv_frame); | 1034 | EXPORT_SYMBOL(hci_recv_frame); |
1035 | 1035 | ||
1036 | static int hci_reassembly(struct hci_dev *hdev, int type, void *data, | ||
1037 | int count, __u8 index, gfp_t gfp_mask) | ||
1038 | { | ||
1039 | int len = 0; | ||
1040 | int hlen = 0; | ||
1041 | int remain = count; | ||
1042 | struct sk_buff *skb; | ||
1043 | struct bt_skb_cb *scb; | ||
1044 | |||
1045 | if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || | ||
1046 | index >= NUM_REASSEMBLY) | ||
1047 | return -EILSEQ; | ||
1048 | |||
1049 | skb = hdev->reassembly[index]; | ||
1050 | |||
1051 | if (!skb) { | ||
1052 | switch (type) { | ||
1053 | case HCI_ACLDATA_PKT: | ||
1054 | len = HCI_MAX_FRAME_SIZE; | ||
1055 | hlen = HCI_ACL_HDR_SIZE; | ||
1056 | break; | ||
1057 | case HCI_EVENT_PKT: | ||
1058 | len = HCI_MAX_EVENT_SIZE; | ||
1059 | hlen = HCI_EVENT_HDR_SIZE; | ||
1060 | break; | ||
1061 | case HCI_SCODATA_PKT: | ||
1062 | len = HCI_MAX_SCO_SIZE; | ||
1063 | hlen = HCI_SCO_HDR_SIZE; | ||
1064 | break; | ||
1065 | } | ||
1066 | |||
1067 | skb = bt_skb_alloc(len, gfp_mask); | ||
1068 | if (!skb) | ||
1069 | return -ENOMEM; | ||
1070 | |||
1071 | scb = (void *) skb->cb; | ||
1072 | scb->expect = hlen; | ||
1073 | scb->pkt_type = type; | ||
1074 | |||
1075 | skb->dev = (void *) hdev; | ||
1076 | hdev->reassembly[index] = skb; | ||
1077 | } | ||
1078 | |||
1079 | while (count) { | ||
1080 | scb = (void *) skb->cb; | ||
1081 | len = min(scb->expect, (__u16)count); | ||
1082 | |||
1083 | memcpy(skb_put(skb, len), data, len); | ||
1084 | |||
1085 | count -= len; | ||
1086 | data += len; | ||
1087 | scb->expect -= len; | ||
1088 | remain = count; | ||
1089 | |||
1090 | switch (type) { | ||
1091 | case HCI_EVENT_PKT: | ||
1092 | if (skb->len == HCI_EVENT_HDR_SIZE) { | ||
1093 | struct hci_event_hdr *h = hci_event_hdr(skb); | ||
1094 | scb->expect = h->plen; | ||
1095 | |||
1096 | if (skb_tailroom(skb) < scb->expect) { | ||
1097 | kfree_skb(skb); | ||
1098 | hdev->reassembly[index] = NULL; | ||
1099 | return -ENOMEM; | ||
1100 | } | ||
1101 | } | ||
1102 | break; | ||
1103 | |||
1104 | case HCI_ACLDATA_PKT: | ||
1105 | if (skb->len == HCI_ACL_HDR_SIZE) { | ||
1106 | struct hci_acl_hdr *h = hci_acl_hdr(skb); | ||
1107 | scb->expect = __le16_to_cpu(h->dlen); | ||
1108 | |||
1109 | if (skb_tailroom(skb) < scb->expect) { | ||
1110 | kfree_skb(skb); | ||
1111 | hdev->reassembly[index] = NULL; | ||
1112 | return -ENOMEM; | ||
1113 | } | ||
1114 | } | ||
1115 | break; | ||
1116 | |||
1117 | case HCI_SCODATA_PKT: | ||
1118 | if (skb->len == HCI_SCO_HDR_SIZE) { | ||
1119 | struct hci_sco_hdr *h = hci_sco_hdr(skb); | ||
1120 | scb->expect = h->dlen; | ||
1121 | |||
1122 | if (skb_tailroom(skb) < scb->expect) { | ||
1123 | kfree_skb(skb); | ||
1124 | hdev->reassembly[index] = NULL; | ||
1125 | return -ENOMEM; | ||
1126 | } | ||
1127 | } | ||
1128 | break; | ||
1129 | } | ||
1130 | |||
1131 | if (scb->expect == 0) { | ||
1132 | /* Complete frame */ | ||
1133 | |||
1134 | bt_cb(skb)->pkt_type = type; | ||
1135 | hci_recv_frame(skb); | ||
1136 | |||
1137 | hdev->reassembly[index] = NULL; | ||
1138 | return remain; | ||
1139 | } | ||
1140 | } | ||
1141 | |||
1142 | return remain; | ||
1143 | } | ||
1144 | |||
1036 | /* Receive packet type fragment */ | 1145 | /* Receive packet type fragment */ |
1037 | #define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 1]) | 1146 | #define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 1]) |
1038 | 1147 | ||