diff options
author | Suraj Sumangala <suraj@atheros.com> | 2010-07-14 03:32:18 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2010-07-21 13:39:12 -0400 |
commit | f39a3c06404d01ef2ce47e821bc778dfb1836df9 (patch) | |
tree | b27dfd8c823bf6ed8c520f8fc84e361cba24238a /net | |
parent | 33e882a5f2301a23a85ef2994e30fd9f48d39d9b (diff) |
Bluetooth: Modified hci_recv_fragment() to use hci_reassembly helper
Modified packet based reassembly function hci_recv_fragment() to use
hci_reassembly()
Signed-off-by: Suraj Sumangala <suraj@atheros.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 85 |
1 files changed, 11 insertions, 74 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 477c4a60a079..451e266840ad 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -1142,87 +1142,24 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, | |||
1142 | return remain; | 1142 | return remain; |
1143 | } | 1143 | } |
1144 | 1144 | ||
1145 | /* Receive packet type fragment */ | ||
1146 | #define __reassembly(hdev, type) ((hdev)->reassembly[(type) - 1]) | ||
1147 | |||
1148 | int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) | 1145 | int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) |
1149 | { | 1146 | { |
1147 | int rem = 0; | ||
1148 | |||
1150 | if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) | 1149 | if (type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) |
1151 | return -EILSEQ; | 1150 | return -EILSEQ; |
1152 | 1151 | ||
1153 | while (count) { | 1152 | do { |
1154 | struct sk_buff *skb = __reassembly(hdev, type); | 1153 | rem = hci_reassembly(hdev, type, data, count, |
1155 | struct { int expect; } *scb; | 1154 | type - 1, GFP_ATOMIC); |
1156 | int len = 0; | 1155 | if (rem < 0) |
1157 | 1156 | return rem; | |
1158 | if (!skb) { | ||
1159 | /* Start of the frame */ | ||
1160 | |||
1161 | switch (type) { | ||
1162 | case HCI_EVENT_PKT: | ||
1163 | if (count >= HCI_EVENT_HDR_SIZE) { | ||
1164 | struct hci_event_hdr *h = data; | ||
1165 | len = HCI_EVENT_HDR_SIZE + h->plen; | ||
1166 | } else | ||
1167 | return -EILSEQ; | ||
1168 | break; | ||
1169 | |||
1170 | case HCI_ACLDATA_PKT: | ||
1171 | if (count >= HCI_ACL_HDR_SIZE) { | ||
1172 | struct hci_acl_hdr *h = data; | ||
1173 | len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen); | ||
1174 | } else | ||
1175 | return -EILSEQ; | ||
1176 | break; | ||
1177 | |||
1178 | case HCI_SCODATA_PKT: | ||
1179 | if (count >= HCI_SCO_HDR_SIZE) { | ||
1180 | struct hci_sco_hdr *h = data; | ||
1181 | len = HCI_SCO_HDR_SIZE + h->dlen; | ||
1182 | } else | ||
1183 | return -EILSEQ; | ||
1184 | break; | ||
1185 | } | ||
1186 | |||
1187 | skb = bt_skb_alloc(len, GFP_ATOMIC); | ||
1188 | if (!skb) { | ||
1189 | BT_ERR("%s no memory for packet", hdev->name); | ||
1190 | return -ENOMEM; | ||
1191 | } | ||
1192 | |||
1193 | skb->dev = (void *) hdev; | ||
1194 | bt_cb(skb)->pkt_type = type; | ||
1195 | |||
1196 | __reassembly(hdev, type) = skb; | ||
1197 | |||
1198 | scb = (void *) skb->cb; | ||
1199 | scb->expect = len; | ||
1200 | } else { | ||
1201 | /* Continuation */ | ||
1202 | |||
1203 | scb = (void *) skb->cb; | ||
1204 | len = scb->expect; | ||
1205 | } | ||
1206 | |||
1207 | len = min(len, count); | ||
1208 | |||
1209 | memcpy(skb_put(skb, len), data, len); | ||
1210 | |||
1211 | scb->expect -= len; | ||
1212 | |||
1213 | if (scb->expect == 0) { | ||
1214 | /* Complete frame */ | ||
1215 | 1157 | ||
1216 | __reassembly(hdev, type) = NULL; | 1158 | data += (count - rem); |
1159 | count = rem; | ||
1160 | } while (count); | ||
1217 | 1161 | ||
1218 | bt_cb(skb)->pkt_type = type; | 1162 | return rem; |
1219 | hci_recv_frame(skb); | ||
1220 | } | ||
1221 | |||
1222 | count -= len; data += len; | ||
1223 | } | ||
1224 | |||
1225 | return 0; | ||
1226 | } | 1163 | } |
1227 | EXPORT_SYMBOL(hci_recv_fragment); | 1164 | EXPORT_SYMBOL(hci_recv_fragment); |
1228 | 1165 | ||